Full Code of nareix/joy4 for AI

master 05a4ffbb5369 cached
62 files
376.2 KB
130.3k tokens
1164 symbols
1 requests
Download .txt
Showing preview only (395K chars total). Download the full file or copy to clipboard to get everything.
Repository: nareix/joy4
Branch: master
Commit: 05a4ffbb5369
Files: 62
Total size: 376.2 KB

Directory structure:
gitextract_naask5op/

├── LICENSE
├── README.md
├── av/
│   ├── av.go
│   ├── avconv/
│   │   └── avconv.go
│   ├── avutil/
│   │   └── avutil.go
│   ├── pktque/
│   │   ├── buf.go
│   │   ├── filters.go
│   │   └── timeline.go
│   ├── pubsub/
│   │   └── queue.go
│   └── transcode/
│       └── transcode.go
├── cgo/
│   └── ffmpeg/
│       ├── audio.go
│       ├── ffmpeg.go
│       ├── ffmpeg.h
│       └── video.go
├── codec/
│   ├── aacparser/
│   │   └── parser.go
│   ├── codec.go
│   ├── fake/
│   │   └── fake.go
│   └── h264parser/
│       ├── parser.go
│       └── parser_test.go
├── doc.go
├── examples/
│   ├── audio_decode/
│   │   └── main.go
│   ├── http_flv_and_rtmp_server/
│   │   └── main.go
│   ├── open_probe_file/
│   │   └── main.go
│   ├── rtmp_publish/
│   │   └── main.go
│   ├── rtmp_server_channels/
│   │   └── main.go
│   ├── rtmp_server_proxy/
│   │   └── main.go
│   ├── rtmp_server_speex_to_aac/
│   │   └── main.go
│   └── transcode/
│       └── main.go
├── format/
│   ├── aac/
│   │   └── aac.go
│   ├── flv/
│   │   ├── flv.go
│   │   └── flvio/
│   │       ├── amf0.go
│   │       └── flvio.go
│   ├── format.go
│   ├── mp4/
│   │   ├── demuxer.go
│   │   ├── handler.go
│   │   ├── mp4io/
│   │   │   ├── atoms.go
│   │   │   ├── gen/
│   │   │   │   ├── gen.go
│   │   │   │   └── pattern.go
│   │   │   └── mp4io.go
│   │   ├── muxer.go
│   │   └── stream.go
│   ├── rtmp/
│   │   └── rtmp.go
│   ├── rtsp/
│   │   ├── client.go
│   │   ├── conn.go
│   │   ├── sdp/
│   │   │   ├── parser.go
│   │   │   └── parser_test.go
│   │   └── stream.go
│   └── ts/
│       ├── demuxer.go
│       ├── handler.go
│       ├── muxer.go
│       ├── stream.go
│       └── tsio/
│           ├── checksum.go
│           └── tsio.go
└── utils/
    └── bits/
        ├── bits.go
        ├── bits_test.go
        ├── bufio/
        │   └── bufio.go
        ├── golomb_reader.go
        └── pio/
            ├── pio.go
            ├── reader.go
            ├── vec.go
            ├── vec_test.go
            └── writer.go

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2017 

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# PLEASE USE joy5 INSTEAD

[joy5](https://github.com/nareix/joy5)

- High performance Copy-on-write gop cache [code](https://github.com/nareix/joy5/blob/master/cmd/avtool/pubsub.go)
- Better av.Packet design [code](https://github.com/nareix/joy5/blob/master/av/av.go)

# JOY4

> Golang audio/video library and streaming server

JOY4 is powerful library written in golang, well-designed interface makes a few lines of code can do a lot of things such as reading, writing, transcoding among variety media formats, or setting up high-performance live streaming server.

# Features 

Well-designed and easy-to-use interfaces:

- Muxer / Demuxer ([doc](https://godoc.org/github.com/nareix/joy4/av#Demuxer) [example](https://github.com/nareix/joy4/blob/master/examples/open_probe_file/main.go))
- Audio Decoder ([doc](https://godoc.org/github.com/nareix/joy4/av#AudioDecoder) [example](https://github.com/nareix/joy4/blob/master/examples/audio_decode/main.go))
- Transcoding ([doc](https://godoc.org/github.com/nareix/joy4/av/transcode) [example](https://github.com/nareix/joy4/blob/master/examples/transcode/main.go))
- Streaming server ([example](https://github.com/nareix/joy4/blob/master/examples/http_flv_and_rtmp_server/main.go))

Support container formats:

- MP4
- MPEG-TS
- FLV
- AAC (ADTS)

RTSP Client
- High level camera bug tolerance
- Support STAP-A

RTMP Client
- Support publishing to nginx-rtmp-server
- Support playing

RTMP / HTTP-FLV Server 
- Support publishing clients: OBS / ffmpeg / Flash Player (>8)
- Support playing clients: Flash Player 11 / VLC / ffplay / mpv
- High performance


Publisher-subscriber packet buffer queue ([doc](https://godoc.org/github.com/nareix/joy4/av/pubsub))

- Customize publisher buffer time and subscriber read position


- Multiple channels live streaming ([example](https://github.com/nareix/joy4/blob/master/examples/rtmp_server_channels/main.go))

Packet filters ([doc](https://godoc.org/github.com/nareix/joy4/av/pktque))

- Wait first keyframe
- Fix timestamp
- Make A/V sync
- Customize ([example](https://github.com/nareix/joy4/blob/master/examples/rtmp_server_channels/main.go#L19))

FFMPEG Golang-style binding ([doc](https://godoc.org/github.com/nareix/joy4/cgo/ffmpeg))
- Audio Encoder / Decoder
- Video Decoder
- Audio Resampler

Support codec and container parsers:

- H264 SPS/PPS/AVCDecoderConfigure parser ([doc](https://godoc.org/github.com/nareix/joy4/codec/h264parser))
- AAC ADTSHeader/MPEG4AudioConfig parser ([doc](https://godoc.org/github.com/nareix/joy4/codec/aacparser))
- MP4 Atoms parser ([doc](https://godoc.org/github.com/nareix/joy4/format/mp4/mp4io))
- FLV AMF0 object parser ([doc](https://godoc.org/github.com/nareix/joy4/format/flv/flvio))

# Requirements

Go version >= 1.6

ffmpeg version >= 3.0 (optional)

# TODO

HLS / MPEG-DASH Server

ffmpeg.VideoEncoder / ffmpeg.SWScale

# License

MIT


================================================
FILE: av/av.go
================================================

// Package av defines basic interfaces and data structures of container demux/mux and audio encode/decode.
package av

import (
	"fmt"
	"time"
)

// Audio sample format.
type SampleFormat uint8

const (
	U8 = SampleFormat(iota + 1) // 8-bit unsigned integer
	S16 // signed 16-bit integer
	S32 // signed 32-bit integer
	FLT // 32-bit float
	DBL // 64-bit float
	U8P // 8-bit unsigned integer in planar
	S16P // signed 16-bit integer in planar
	S32P // signed 32-bit integer in planar
	FLTP // 32-bit float in planar
	DBLP // 64-bit float in planar
	U32 // unsigned 32-bit integer
)

func (self SampleFormat) BytesPerSample() int {
	switch self {
	case U8, U8P:
		return 1
	case S16, S16P:
		return 2
	case FLT, FLTP, S32, S32P, U32:
		return 4
	case DBL, DBLP:
		return 8
	default:
		return 0
	}
}

func (self SampleFormat) String() string {
	switch self {
	case U8:
		return "U8"
	case S16:
		return "S16"
	case S32:
		return "S32"
	case FLT:
		return "FLT"
	case DBL:
		return "DBL"
	case U8P:
		return "U8P"
	case S16P:
		return "S16P"
	case FLTP:
		return "FLTP"
	case DBLP:
		return "DBLP"
	case U32:
		return "U32"
	default:
		return "?"
	}
}

// Check if this sample format is in planar.
func (self SampleFormat) IsPlanar() bool {
	switch self {
	case S16P, S32P, FLTP, DBLP:
		return true
	default:
		return false
	}
}

// Audio channel layout.
type ChannelLayout uint16

func (self ChannelLayout) String() string {
	return fmt.Sprintf("%dch", self.Count())
}

const (
	CH_FRONT_CENTER = ChannelLayout(1 << iota)
	CH_FRONT_LEFT
	CH_FRONT_RIGHT
	CH_BACK_CENTER
	CH_BACK_LEFT
	CH_BACK_RIGHT
	CH_SIDE_LEFT
	CH_SIDE_RIGHT
	CH_LOW_FREQ
	CH_NR

	CH_MONO     = ChannelLayout(CH_FRONT_CENTER)
	CH_STEREO   = ChannelLayout(CH_FRONT_LEFT | CH_FRONT_RIGHT)
	CH_2_1      = ChannelLayout(CH_STEREO | CH_BACK_CENTER)
	CH_2POINT1  = ChannelLayout(CH_STEREO | CH_LOW_FREQ)
	CH_SURROUND = ChannelLayout(CH_STEREO | CH_FRONT_CENTER)
	CH_3POINT1  = ChannelLayout(CH_SURROUND | CH_LOW_FREQ)
	// TODO: add all channel_layout in ffmpeg
)

func (self ChannelLayout) Count() (n int) {
	for self != 0 {
		n++
		self = (self - 1) & self
	}
	return
}

// Video/Audio codec type. can be H264/AAC/SPEEX/...
type CodecType uint32

var (
	H264 = MakeVideoCodecType(avCodecTypeMagic + 1)
	AAC       = MakeAudioCodecType(avCodecTypeMagic + 1)
	PCM_MULAW = MakeAudioCodecType(avCodecTypeMagic + 2)
	PCM_ALAW  = MakeAudioCodecType(avCodecTypeMagic + 3)
	SPEEX = MakeAudioCodecType(avCodecTypeMagic + 4)
	NELLYMOSER = MakeAudioCodecType(avCodecTypeMagic + 5)
)

const codecTypeAudioBit = 0x1
const codecTypeOtherBits = 1

func (self CodecType) String() string {
	switch self {
	case H264:
		return "H264"
	case AAC:
		return "AAC"
	case PCM_MULAW:
		return "PCM_MULAW"
	case PCM_ALAW:
		return "PCM_ALAW"
	case SPEEX:
		return "SPEEX"
	case NELLYMOSER:
		return "NELLYMOSER"
	}
	return ""
}

func (self CodecType) IsAudio() bool {
	return self&codecTypeAudioBit != 0
}

func (self CodecType) IsVideo() bool {
	return self&codecTypeAudioBit == 0
}

// Make a new audio codec type.
func MakeAudioCodecType(base uint32) (c CodecType) {
	c = CodecType(base)<<codecTypeOtherBits | CodecType(codecTypeAudioBit)
	return
}

// Make a new video codec type.
func MakeVideoCodecType(base uint32) (c CodecType) {
	c = CodecType(base) << codecTypeOtherBits
	return
}

const avCodecTypeMagic = 233333

// CodecData is some important bytes for initializing audio/video decoder,
// can be converted to VideoCodecData or AudioCodecData using:
//
//     codecdata.(AudioCodecData) or codecdata.(VideoCodecData)
// 
// for H264, CodecData is AVCDecoderConfigure bytes, includes SPS/PPS.
type CodecData interface {
	Type() CodecType // Video/Audio codec type
}

type VideoCodecData interface {
	CodecData
	Width() int // Video width
	Height() int // Video height
}

type AudioCodecData interface {
	CodecData
	SampleFormat() SampleFormat // audio sample format
	SampleRate() int // audio sample rate
	ChannelLayout() ChannelLayout // audio channel layout
	PacketDuration([]byte) (time.Duration, error) // get audio compressed packet duration
}

type PacketWriter interface {
	WritePacket(Packet) error
}

type PacketReader interface {
	ReadPacket() (Packet,error)
}

// Muxer describes the steps of writing compressed audio/video packets into container formats like MP4/FLV/MPEG-TS.
// 
// Container formats, rtmp.Conn, and transcode.Muxer implements Muxer interface.
type Muxer interface {
	WriteHeader([]CodecData) error // write the file header
	PacketWriter // write compressed audio/video packets
	WriteTrailer() error // finish writing file, this func can be called only once
}

// Muxer with Close() method
type MuxCloser interface {
	Muxer
	Close() error
}

// Demuxer can read compressed audio/video packets from container formats like MP4/FLV/MPEG-TS.
type Demuxer interface {
	PacketReader // read compressed audio/video packets
	Streams() ([]CodecData, error) // reads the file header, contains video/audio meta infomations
}

// Demuxer with Close() method
type DemuxCloser interface {
	Demuxer
	Close() error
}

// Packet stores compressed audio/video data.
type Packet struct {
	IsKeyFrame      bool // video packet is key frame
	Idx             int8 // stream index in container format
	CompositionTime time.Duration // packet presentation time minus decode time for H264 B-Frame
	Time time.Duration // packet decode time
	Data            []byte // packet data
}

// Raw audio frame.
type AudioFrame struct {
	SampleFormat  SampleFormat // audio sample format, e.g: S16,FLTP,...
	ChannelLayout ChannelLayout // audio channel layout, e.g: CH_MONO,CH_STEREO,...
	SampleCount   int // sample count in this frame
	SampleRate    int // sample rate
	Data          [][]byte // data array for planar format len(Data) > 1
}

func (self AudioFrame) Duration() time.Duration {
	return time.Second * time.Duration(self.SampleCount) / time.Duration(self.SampleRate)
}

// Check this audio frame has same format as other audio frame.
func (self AudioFrame) HasSameFormat(other AudioFrame) bool {
	if self.SampleRate != other.SampleRate {
		return false
	}
	if self.ChannelLayout != other.ChannelLayout {
		return false
	}
	if self.SampleFormat != other.SampleFormat {
		return false
	}
	return true
}

// Split sample audio sample from this frame.
func (self AudioFrame) Slice(start int, end int) (out AudioFrame) {
	if start > end {
		panic(fmt.Sprintf("av: AudioFrame split failed start=%d end=%d invalid", start, end))
	}
	out = self
	out.Data = append([][]byte(nil), out.Data...)
	out.SampleCount = end - start
	size := self.SampleFormat.BytesPerSample()
	for i := range out.Data {
		out.Data[i] = out.Data[i][start*size : end*size]
	}
	return
}

// Concat two audio frames.
func (self AudioFrame) Concat(in AudioFrame) (out AudioFrame) {
	out = self
	out.Data = append([][]byte(nil), out.Data...)
	out.SampleCount += in.SampleCount
	for i := range out.Data {
		out.Data[i] = append(out.Data[i], in.Data[i]...)
	}
	return
}

// AudioEncoder can encode raw audio frame into compressed audio packets.
// cgo/ffmpeg inplements AudioEncoder, using ffmpeg.NewAudioEncoder to create it.
type AudioEncoder interface {
	CodecData() (AudioCodecData, error) // encoder's codec data can put into container
	Encode(AudioFrame) ([][]byte, error) // encode raw audio frame into compressed pakcet(s)
	Close() // close encoder, free cgo contexts
	SetSampleRate(int) (error) // set encoder sample rate
	SetChannelLayout(ChannelLayout) (error) // set encoder channel layout
	SetSampleFormat(SampleFormat) (error) // set encoder sample format
	SetBitrate(int) (error) // set encoder bitrate
	SetOption(string,interface{}) (error) // encoder setopt, in ffmpeg is av_opt_set_dict()
	GetOption(string,interface{}) (error) // encoder getopt
}

// AudioDecoder can decode compressed audio packets into raw audio frame.
// use ffmpeg.NewAudioDecoder to create it.
type AudioDecoder interface {
	Decode([]byte) (bool, AudioFrame, error) // decode one compressed audio packet
	Close() // close decode, free cgo contexts
}

// AudioResampler can convert raw audio frames in different sample rate/format/channel layout.
type AudioResampler interface {
	Resample(AudioFrame) (AudioFrame, error) // convert raw audio frames
}



================================================
FILE: av/avconv/avconv.go
================================================
package avconv

import (
	"fmt"
	"io"
	"time"
	"github.com/nareix/joy4/av/avutil"
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/av/pktque"
	"github.com/nareix/joy4/av/transcode"
)

var Debug bool

type Option struct {
	Transcode bool
	Args []string
}

type Options struct {
	OutputCodecTypes []av.CodecType
}

type Demuxer struct {
	transdemux *transcode.Demuxer
	streams []av.CodecData
	Options
	Demuxer av.Demuxer
}

func (self *Demuxer) Close() (err error) {
	if self.transdemux != nil {
		return self.transdemux.Close()
	}
	return
}

func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
	if err = self.prepare(); err != nil {
		return
	}
	streams = self.streams
	return
}

func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
	if err = self.prepare(); err != nil {
		return
	}
	return self.transdemux.ReadPacket()
}

func (self *Demuxer) prepare() (err error) {
	if self.transdemux != nil {
		return
	}

	/*
	var streams []av.CodecData
	if streams, err = self.Demuxer.Streams(); err != nil {
		return
	}
	*/

	supports := self.Options.OutputCodecTypes

	transopts := transcode.Options{}
	transopts.FindAudioDecoderEncoder = func(codec av.AudioCodecData, i int) (ok bool, dec av.AudioDecoder, enc av.AudioEncoder, err error) {
		if len(supports) == 0 {
			return
		}

		support := false
		for _, typ := range supports {
			if typ == codec.Type() {
				support = true
			}
		}

		if support {
			return
		}
		ok = true

		var enctype av.CodecType
		for _, typ:= range supports {
			if typ.IsAudio() {
				if enc, _ = avutil.DefaultHandlers.NewAudioEncoder(typ); enc != nil {
					enctype = typ
					break
				}
			}
		}
		if enc == nil {
			err = fmt.Errorf("avconv: convert %s->%s failed", codec.Type(), enctype)
			return
		}

		// TODO: support per stream option
		// enc.SetSampleRate ...

		if dec, err = avutil.DefaultHandlers.NewAudioDecoder(codec); err != nil {
			err = fmt.Errorf("avconv: decode %s failed", codec.Type())
			return
		}

		return
	}

	self.transdemux = &transcode.Demuxer{
		Options: transopts,
		Demuxer: self.Demuxer,
	}
	if self.streams, err = self.transdemux.Streams(); err != nil {
		return
	}

	return
}

func ConvertCmdline(args []string) (err error) {
	output := ""
	input := ""
	flagi := false
	flagv := false
	flagt := false
	flagre := false
	duration := time.Duration(0)
	options := Options{}

	for _, arg := range args {
		switch arg {
		case "-i":
			flagi = true

		case "-v":
			flagv = true

		case "-t":
			flagt = true

		case "-re":
			flagre = true

		default:
			switch {
			case flagi:
				flagi = false
				input = arg

			case flagt:
				flagt = false
				var f float64
				fmt.Sscanf(arg, "%f", &f)
				duration = time.Duration(f*float64(time.Second))

			default:
				output = arg
			}
		}
	}

	if input == "" {
		err = fmt.Errorf("avconv: input file not specified")
		return
	}

	if output == "" {
		err = fmt.Errorf("avconv: output file not specified")
		return
	}

	var demuxer av.DemuxCloser
	var muxer av.MuxCloser

	if demuxer, err = avutil.Open(input); err != nil {
		return
	}
	defer demuxer.Close()

	var handler avutil.RegisterHandler
	if handler, muxer, err = avutil.DefaultHandlers.FindCreate(output); err != nil {
		return
	}
	defer muxer.Close()

	options.OutputCodecTypes = handler.CodecTypes

	convdemux := &Demuxer{
		Options: options,
		Demuxer: demuxer,
	}
	defer convdemux.Close()

	var streams []av.CodecData
	if streams, err = demuxer.Streams(); err != nil {
		return
	}

	var convstreams []av.CodecData
	if convstreams, err = convdemux.Streams(); err != nil {
		return
	}

	if flagv {
		for _, stream := range streams {
			fmt.Print(stream.Type(), " ")
		}
		fmt.Print("-> ")
		for _, stream := range convstreams {
			fmt.Print(stream.Type(), " ")
		}
		fmt.Println()
	}

	if err = muxer.WriteHeader(convstreams); err != nil {
		return
	}

	filters := pktque.Filters{}
	if flagre {
		filters = append(filters, &pktque.Walltime{})
	}
	filterdemux := &pktque.FilterDemuxer{
		Demuxer: convdemux,
		Filter: filters,
	}

	for {
		var pkt av.Packet
		if pkt, err = filterdemux.ReadPacket(); err != nil {
			if err == io.EOF {
				err = nil
				break
			}
			return
		}
		if flagv {
			fmt.Println(pkt.Idx, pkt.Time, len(pkt.Data), pkt.IsKeyFrame)
		}
		if duration != 0 && pkt.Time > duration {
			break
		}
		if err = muxer.WritePacket(pkt); err != nil {
			return
		}
	}

	if err = muxer.WriteTrailer(); err != nil {
		return
	}

	return
}



================================================
FILE: av/avutil/avutil.go
================================================
package avutil

import (
	"io"
	"strings"
	"fmt"
	"bytes"
	"github.com/nareix/joy4/av"
	"net/url"
	"os"
	"path"
)

type HandlerDemuxer struct {
	av.Demuxer
	r io.ReadCloser
}

func (self *HandlerDemuxer) Close() error {
	return self.r.Close()
}

type HandlerMuxer struct {
	av.Muxer
	w io.WriteCloser
	stage int
}

func (self *HandlerMuxer) WriteHeader(streams []av.CodecData) (err error) {
	if self.stage == 0 {
		if err = self.Muxer.WriteHeader(streams); err != nil {
			return
		}
		self.stage++
	}
	return
}

func (self *HandlerMuxer) WriteTrailer() (err error) {
	if self.stage == 1 {
		self.stage++
		if err = self.Muxer.WriteTrailer(); err != nil {
			return
		}
	}
	return
}

func (self *HandlerMuxer) Close() (err error) {
	if err = self.WriteTrailer(); err != nil {
		return
	}
	return self.w.Close()
}

type RegisterHandler struct {
	Ext string
	ReaderDemuxer func(io.Reader)av.Demuxer
	WriterMuxer func(io.Writer)av.Muxer
	UrlMuxer func(string)(bool,av.MuxCloser,error)
	UrlDemuxer func(string)(bool,av.DemuxCloser,error)
	UrlReader func(string)(bool,io.ReadCloser,error)
	Probe func([]byte)bool
	AudioEncoder func(av.CodecType)(av.AudioEncoder,error)
	AudioDecoder func(av.AudioCodecData)(av.AudioDecoder,error)
	ServerDemuxer func(string)(bool,av.DemuxCloser,error)
	ServerMuxer func(string)(bool,av.MuxCloser,error)
	CodecTypes []av.CodecType
}

type Handlers struct {
	handlers []RegisterHandler
}

func (self *Handlers) Add(fn func(*RegisterHandler)) {
	handler := &RegisterHandler{}
	fn(handler)
	self.handlers = append(self.handlers, *handler)
}

func (self *Handlers) openUrl(u *url.URL, uri string) (r io.ReadCloser, err error) {
	if u != nil && u.Scheme != "" {
		for _, handler := range self.handlers {
			if handler.UrlReader != nil {
				var ok bool
				if ok, r, err = handler.UrlReader(uri); ok {
					return
				}
			}
		}
		err = fmt.Errorf("avutil: openUrl %s failed", uri)
	} else {
		r, err = os.Open(uri)
	}
	return
}

func (self *Handlers) createUrl(u *url.URL, uri string) (w io.WriteCloser, err error) {
	w, err = os.Create(uri)
	return
}

func (self *Handlers) NewAudioEncoder(typ av.CodecType) (enc av.AudioEncoder, err error) {
	for _, handler := range self.handlers {
		if handler.AudioEncoder != nil {
			if enc, _ = handler.AudioEncoder(typ); enc != nil {
				return
			}
		}
	}
	err = fmt.Errorf("avutil: encoder", typ, "not found")
	return
}

func (self *Handlers) NewAudioDecoder(codec av.AudioCodecData) (dec av.AudioDecoder, err error) {
	for _, handler := range self.handlers {
		if handler.AudioDecoder != nil {
			if dec, _ = handler.AudioDecoder(codec); dec != nil {
				return
			}
		}
	}
	err = fmt.Errorf("avutil: decoder", codec.Type(), "not found")
	return
}

func (self *Handlers) Open(uri string) (demuxer av.DemuxCloser, err error) {
	listen := false
	if strings.HasPrefix(uri, "listen:") {
		uri = uri[len("listen:"):]
		listen = true
	}

	for _, handler := range self.handlers {
		if listen {
			if handler.ServerDemuxer != nil {
				var ok bool
				if ok, demuxer, err = handler.ServerDemuxer(uri); ok {
					return
				}
			}
		} else {
			if handler.UrlDemuxer != nil {
				var ok bool
				if ok, demuxer, err = handler.UrlDemuxer(uri); ok {
					return
				}
			}
		}
	}

	var r io.ReadCloser
	var ext string
	var u *url.URL
	if u, _ = url.Parse(uri); u != nil && u.Scheme != "" {
		ext = path.Ext(u.Path)
	} else {
		ext = path.Ext(uri)
	}

	if ext != "" {
		for _, handler := range self.handlers {
			if handler.Ext == ext {
				if handler.ReaderDemuxer != nil {
					if r, err = self.openUrl(u, uri); err != nil {
						return
					}
					demuxer = &HandlerDemuxer{
						Demuxer: handler.ReaderDemuxer(r),
						r: r,
					}
					return
				}
			}
		}
	}

	var probebuf [1024]byte
	if r, err = self.openUrl(u, uri); err != nil {
		return
	}
	if _, err = io.ReadFull(r, probebuf[:]); err != nil {
		return
	}

	for _, handler := range self.handlers {
		if handler.Probe != nil && handler.Probe(probebuf[:]) && handler.ReaderDemuxer != nil {
			var _r io.Reader
			if rs, ok := r.(io.ReadSeeker); ok {
				if _, err = rs.Seek(0, 0); err != nil {
					return
				}
				_r = rs
			} else {
				_r = io.MultiReader(bytes.NewReader(probebuf[:]), r)
			}
			demuxer = &HandlerDemuxer{
				Demuxer: handler.ReaderDemuxer(_r),
				r: r,
			}
			return
		}
	}

	r.Close()
	err = fmt.Errorf("avutil: open %s failed", uri)
	return
}

func (self *Handlers) Create(uri string) (muxer av.MuxCloser, err error) {
	_, muxer, err = self.FindCreate(uri)
	return
}

func (self *Handlers) FindCreate(uri string) (handler RegisterHandler, muxer av.MuxCloser, err error) {
	listen := false
	if strings.HasPrefix(uri, "listen:") {
		uri = uri[len("listen:"):]
		listen = true
	}

	for _, handler = range self.handlers {
		if listen {
			if handler.ServerMuxer != nil {
				var ok bool
				if ok, muxer, err = handler.ServerMuxer(uri); ok {
					return
				}
			}
		} else {
			if handler.UrlMuxer != nil {
				var ok bool
				if ok, muxer, err = handler.UrlMuxer(uri); ok {
					return
				}
			}
		}
	}

	var ext string
	var u *url.URL
	if u, _ = url.Parse(uri); u != nil && u.Scheme != "" {
		ext = path.Ext(u.Path)
	} else {
		ext = path.Ext(uri)
	}

	if ext != "" {
		for _, handler = range self.handlers {
			if handler.Ext == ext && handler.WriterMuxer != nil {
				var w io.WriteCloser
				if w, err = self.createUrl(u, uri); err != nil {
					return
				}
				muxer = &HandlerMuxer{
					Muxer: handler.WriterMuxer(w),
					w: w,
				}
				return
			}
		}
	}

	err = fmt.Errorf("avutil: create muxer %s failed", uri)
	return
}

var DefaultHandlers = &Handlers{}

func Open(url string) (demuxer av.DemuxCloser, err error) {
	return DefaultHandlers.Open(url)
}

func Create(url string) (muxer av.MuxCloser, err error) {
	return DefaultHandlers.Create(url)
}

func CopyPackets(dst av.PacketWriter, src av.PacketReader) (err error) {
	for {
		var pkt av.Packet
		if pkt, err = src.ReadPacket(); err != nil {
			if err == io.EOF {
				break
			}
			return
		}
		if err = dst.WritePacket(pkt); err != nil {
			return
		}
	}
	return
}

func CopyFile(dst av.Muxer, src av.Demuxer) (err error) {
	var streams []av.CodecData
	if streams, err = src.Streams(); err != nil {
		return
	}
	if err = dst.WriteHeader(streams); err != nil {
		return
	}
	if err = CopyPackets(dst, src); err != nil {
		if err != io.EOF {
			return
		}
	}
	if err = dst.WriteTrailer(); err != nil {
		return
	}
	return
}


================================================
FILE: av/pktque/buf.go
================================================
package pktque

import (
	"github.com/nareix/joy4/av"
)

type Buf struct {
	Head, Tail BufPos
	pkts       []av.Packet
	Size       int
	Count      int
}

func NewBuf() *Buf {
	return &Buf{
		pkts: make([]av.Packet, 64),
	}
}

func (self *Buf) Pop() av.Packet {
	if self.Count == 0 {
		panic("pktque.Buf: Pop() when count == 0")
	}

	i := int(self.Head) & (len(self.pkts) - 1)
	pkt := self.pkts[i]
	self.pkts[i] = av.Packet{}
	self.Size -= len(pkt.Data)
	self.Head++
	self.Count--

	return pkt
}

func (self *Buf) grow() {
	newpkts := make([]av.Packet, len(self.pkts)*2)
	for i := self.Head; i.LT(self.Tail); i++ {
		newpkts[int(i)&(len(newpkts)-1)] = self.pkts[int(i)&(len(self.pkts)-1)]
	}
	self.pkts = newpkts
}

func (self *Buf) Push(pkt av.Packet) {
	if self.Count == len(self.pkts) {
		self.grow()
	}
	self.pkts[int(self.Tail)&(len(self.pkts)-1)] = pkt
	self.Tail++
	self.Count++
	self.Size += len(pkt.Data)
}

func (self *Buf) Get(pos BufPos) av.Packet {
	return self.pkts[int(pos)&(len(self.pkts)-1)]
}

func (self *Buf) IsValidPos(pos BufPos) bool {
	return pos.GE(self.Head) && pos.LT(self.Tail)
}

type BufPos int

func (self BufPos) LT(pos BufPos) bool {
	return self-pos < 0
}

func (self BufPos) GE(pos BufPos) bool {
	return self-pos >= 0
}

func (self BufPos) GT(pos BufPos) bool {
	return self-pos > 0
}


================================================
FILE: av/pktque/filters.go
================================================

// Package pktque provides packet Filter interface and structures used by other components.
package pktque

import (
	"time"
	"github.com/nareix/joy4/av"
)

type Filter interface {
	// Change packet time or drop packet
	ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error)
}

// Combine multiple Filters into one, ModifyPacket will be called in order.
type Filters []Filter

func (self Filters) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
	for _, filter := range self {
		if drop, err = filter.ModifyPacket(pkt, streams, videoidx, audioidx); err != nil {
			return
		}
		if drop {
			return
		}
	}
	return
}

// Wrap origin Demuxer and Filter into a new Demuxer, when read this Demuxer filters will be called.
type FilterDemuxer struct {
	av.Demuxer
	Filter Filter
	streams []av.CodecData
	videoidx int
	audioidx int
}

func (self FilterDemuxer) ReadPacket() (pkt av.Packet, err error) {
	if self.streams == nil {
		if self.streams, err = self.Demuxer.Streams(); err != nil {
			return
		}
		for i, stream := range self.streams {
			if stream.Type().IsVideo() {
				self.videoidx = i
			} else if stream.Type().IsAudio() {
				self.audioidx = i
			}
		}
	}

	for {
		if pkt, err = self.Demuxer.ReadPacket(); err != nil {
			return
		}
		var drop bool
		if drop, err = self.Filter.ModifyPacket(&pkt, self.streams, self.videoidx, self.audioidx); err != nil {
			return
		}
		if !drop {
			break
		}
	}

	return
}

// Drop packets until first video key frame arrived.
type WaitKeyFrame struct {
	ok bool
}

func (self *WaitKeyFrame) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
	if !self.ok && pkt.Idx == int8(videoidx) && pkt.IsKeyFrame {
		self.ok = true
	}
	drop = !self.ok
	return
}

// Fix incorrect packet timestamps.
type FixTime struct {
	zerobase time.Duration
	incrbase time.Duration
	lasttime time.Duration
	StartFromZero bool // make timestamp start from zero
	MakeIncrement bool // force timestamp increment
}

func (self *FixTime) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
	if self.StartFromZero {
		if self.zerobase == 0 {
			self.zerobase = pkt.Time
		}
		pkt.Time -= self.zerobase
	}

	if self.MakeIncrement {
		pkt.Time -= self.incrbase
		if self.lasttime == 0 {
			self.lasttime = pkt.Time
		}
		if pkt.Time < self.lasttime || pkt.Time > self.lasttime+time.Millisecond*500 {
			self.incrbase += pkt.Time - self.lasttime
			pkt.Time = self.lasttime
		}
		self.lasttime = pkt.Time
	}

	return
}

// Drop incorrect packets to make A/V sync.
type AVSync struct {
	MaxTimeDiff time.Duration
	time []time.Duration
}

func (self *AVSync) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
	if self.time == nil {
		self.time = make([]time.Duration, len(streams))
		if self.MaxTimeDiff == 0 {
			self.MaxTimeDiff = time.Millisecond*500
		}
	}

	start, end, correctable, correcttime := self.check(int(pkt.Idx))
	if pkt.Time >= start && pkt.Time < end {
		self.time[pkt.Idx] = pkt.Time
	} else {
		if correctable {
			pkt.Time = correcttime
			for i := range self.time {
				self.time[i] = correcttime
			}
		} else {
			drop = true
		}
	}
	return
}

func (self *AVSync) check(i int) (start time.Duration, end time.Duration, correctable bool, correcttime time.Duration) {
	minidx := -1
	maxidx := -1
	for j := range self.time {
		if minidx == -1 || self.time[j] < self.time[minidx] {
			minidx = j
		}
		if maxidx == -1 || self.time[j] > self.time[maxidx] {
			maxidx = j
		}
	}
	allthesame := self.time[minidx] == self.time[maxidx]

	if i == maxidx {
		if allthesame {
			correctable = true
		} else {
			correctable = false
		}
	} else {
		correctable = true
	}

	start = self.time[minidx]
	end = start + self.MaxTimeDiff
	correcttime = start + time.Millisecond*40
	return
}

// Make packets reading speed as same as walltime, effect like ffmpeg -re option.
type Walltime struct {
	firsttime time.Time
}

func (self *Walltime) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
	if pkt.Idx == 0 {
		if self.firsttime.IsZero() {
			self.firsttime = time.Now()
		}
		pkttime := self.firsttime.Add(pkt.Time)
		delta := pkttime.Sub(time.Now())
		if delta > 0 {
			time.Sleep(delta)
		}
	}
	return
}



================================================
FILE: av/pktque/timeline.go
================================================
package pktque

import (
	"time"
)

/*
pop                                   push

     seg                 seg        seg
  |--------|         |---------|   |---|
     20ms                40ms       5ms
----------------- time -------------------->
headtm                               tailtm
*/

type tlSeg struct {
	tm, dur time.Duration
}

type Timeline struct {
	segs []tlSeg
	headtm time.Duration
}

func (self *Timeline) Push(tm time.Duration, dur time.Duration) {
	if len(self.segs) > 0 {
		tail := self.segs[len(self.segs)-1]
		diff := tm-(tail.tm+tail.dur)
		if diff < 0 {
			tm -= diff
		}
	}
	self.segs = append(self.segs, tlSeg{tm, dur})
}

func (self *Timeline) Pop(dur time.Duration) (tm time.Duration) {
	if len(self.segs) == 0 {
		return self.headtm
	}

	tm = self.segs[0].tm
	for dur > 0 && len(self.segs) > 0 {
		seg := &self.segs[0]
		sub := dur
		if seg.dur < sub {
			sub = seg.dur
		}
		seg.dur -= sub
		dur -= sub
		seg.tm += sub
		self.headtm += sub
		if seg.dur == 0 {
			copy(self.segs[0:], self.segs[1:])
			self.segs = self.segs[:len(self.segs)-1]
		}
	}

	return
}



================================================
FILE: av/pubsub/queue.go
================================================
// Packege pubsub implements publisher-subscribers model used in multi-channel streaming.
package pubsub

import (
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/av/pktque"
	"io"
	"sync"
	"time"
)

//        time
// ----------------->
//
// V-A-V-V-A-V-V-A-V-V
// |                 |
// 0        5        10
// head             tail
// oldest          latest
//

// One publisher and multiple subscribers thread-safe packet buffer queue.
type Queue struct {
	buf                      *pktque.Buf
	head, tail               int
	lock                     *sync.RWMutex
	cond                     *sync.Cond
	curgopcount, maxgopcount int
	streams                  []av.CodecData
	videoidx                 int
	closed                   bool
}

func NewQueue() *Queue {
	q := &Queue{}
	q.buf = pktque.NewBuf()
	q.maxgopcount = 2
	q.lock = &sync.RWMutex{}
	q.cond = sync.NewCond(q.lock.RLocker())
	q.videoidx = -1
	return q
}

func (self *Queue) SetMaxGopCount(n int) {
	self.lock.Lock()
	self.maxgopcount = n
	self.lock.Unlock()
	return
}

func (self *Queue) WriteHeader(streams []av.CodecData) error {
	self.lock.Lock()

	self.streams = streams
	for i, stream := range streams {
		if stream.Type().IsVideo() {
			self.videoidx = i
		}
	}
	self.cond.Broadcast()

	self.lock.Unlock()

	return nil
}

func (self *Queue) WriteTrailer() error {
	return nil
}

// After Close() called, all QueueCursor's ReadPacket will return io.EOF.
func (self *Queue) Close() (err error) {
	self.lock.Lock()

	self.closed = true
	self.cond.Broadcast()

	self.lock.Unlock()
	return
}

// Put packet into buffer, old packets will be discared.
func (self *Queue) WritePacket(pkt av.Packet) (err error) {
	self.lock.Lock()

	self.buf.Push(pkt)
	if pkt.Idx == int8(self.videoidx) && pkt.IsKeyFrame {
		self.curgopcount++
	}

	for self.curgopcount >= self.maxgopcount && self.buf.Count > 1 {
		pkt := self.buf.Pop()
		if pkt.Idx == int8(self.videoidx) && pkt.IsKeyFrame {
			self.curgopcount--
		}
		if self.curgopcount < self.maxgopcount {
			break
		}
	}
	//println("shrink", self.curgopcount, self.maxgopcount, self.buf.Head, self.buf.Tail, "count", self.buf.Count, "size", self.buf.Size)

	self.cond.Broadcast()

	self.lock.Unlock()
	return
}

type QueueCursor struct {
	que    *Queue
	pos    pktque.BufPos
	gotpos bool
	init   func(buf *pktque.Buf, videoidx int) pktque.BufPos
}

func (self *Queue) newCursor() *QueueCursor {
	return &QueueCursor{
		que: self,
	}
}

// Create cursor position at latest packet.
func (self *Queue) Latest() *QueueCursor {
	cursor := self.newCursor()
	cursor.init = func(buf *pktque.Buf, videoidx int) pktque.BufPos {
		return buf.Tail
	}
	return cursor
}

// Create cursor position at oldest buffered packet.
func (self *Queue) Oldest() *QueueCursor {
	cursor := self.newCursor()
	cursor.init = func(buf *pktque.Buf, videoidx int) pktque.BufPos {
		return buf.Head
	}
	return cursor
}

// Create cursor position at specific time in buffered packets.
func (self *Queue) DelayedTime(dur time.Duration) *QueueCursor {
	cursor := self.newCursor()
	cursor.init = func(buf *pktque.Buf, videoidx int) pktque.BufPos {
		i := buf.Tail - 1
		if buf.IsValidPos(i) {
			end := buf.Get(i)
			for buf.IsValidPos(i) {
				if end.Time-buf.Get(i).Time > dur {
					break
				}
				i--
			}
		}
		return i
	}
	return cursor
}

// Create cursor position at specific delayed GOP count in buffered packets.
func (self *Queue) DelayedGopCount(n int) *QueueCursor {
	cursor := self.newCursor()
	cursor.init = func(buf *pktque.Buf, videoidx int) pktque.BufPos {
		i := buf.Tail - 1
		if videoidx != -1 {
			for gop := 0; buf.IsValidPos(i) && gop < n; i-- {
				pkt := buf.Get(i)
				if pkt.Idx == int8(self.videoidx) && pkt.IsKeyFrame {
					gop++
				}
			}
		}
		return i
	}
	return cursor
}

func (self *QueueCursor) Streams() (streams []av.CodecData, err error) {
	self.que.cond.L.Lock()
	for self.que.streams == nil && !self.que.closed {
		self.que.cond.Wait()
	}
	if self.que.streams != nil {
		streams = self.que.streams
	} else {
		err = io.EOF
	}
	self.que.cond.L.Unlock()
	return
}

// ReadPacket will not consume packets in Queue, it's just a cursor.
func (self *QueueCursor) ReadPacket() (pkt av.Packet, err error) {
	self.que.cond.L.Lock()
	buf := self.que.buf
	if !self.gotpos {
		self.pos = self.init(buf, self.que.videoidx)
		self.gotpos = true
	}
	for {
		if self.pos.LT(buf.Head) {
			self.pos = buf.Head
		} else if self.pos.GT(buf.Tail) {
			self.pos = buf.Tail
		}
		if buf.IsValidPos(self.pos) {
			pkt = buf.Get(self.pos)
			self.pos++
			break
		}
		if self.que.closed {
			err = io.EOF
			break
		}
		self.que.cond.Wait()
	}
	self.que.cond.L.Unlock()
	return
}


================================================
FILE: av/transcode/transcode.go
================================================

// Package transcoder implements Transcoder based on Muxer/Demuxer and AudioEncoder/AudioDecoder interface.
package transcode

import (
	"fmt"
	"time"
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/av/pktque"
)

var Debug bool

type tStream struct {
	codec av.CodecData
	timeline *pktque.Timeline
	aencodec, adecodec av.AudioCodecData
	aenc av.AudioEncoder
	adec av.AudioDecoder
}

type Options struct {
	// check if transcode is needed, and create the AudioDecoder and AudioEncoder.
	FindAudioDecoderEncoder func(codec av.AudioCodecData, i int) (
		need bool, dec av.AudioDecoder, enc av.AudioEncoder, err error,
	)
}

type Transcoder struct {
	streams                 []*tStream
}

func NewTranscoder(streams []av.CodecData, options Options) (_self *Transcoder, err error) {
	self := &Transcoder{}
	self.streams = []*tStream{}

	for i, stream := range streams {
		ts := &tStream{codec: stream}
		if stream.Type().IsAudio() {
			if options.FindAudioDecoderEncoder != nil {
				var ok bool
				var enc av.AudioEncoder
				var dec av.AudioDecoder
				ok, dec, enc, err = options.FindAudioDecoderEncoder(stream.(av.AudioCodecData), i)
				if ok {
					if err != nil {
						return
					}
					ts.timeline = &pktque.Timeline{}
					if ts.codec, err = enc.CodecData(); err != nil {
						return
					}
					ts.aencodec = ts.codec.(av.AudioCodecData)
					ts.adecodec = stream.(av.AudioCodecData)
					ts.aenc = enc
					ts.adec = dec
				}
			}
		}
		self.streams = append(self.streams, ts)
	}

	_self = self
	return
}

func (self *tStream) audioDecodeAndEncode(inpkt av.Packet) (outpkts []av.Packet, err error) {
	var dur time.Duration
	var frame av.AudioFrame
	var ok bool
	if ok, frame, err = self.adec.Decode(inpkt.Data); err != nil {
		return
	}
	if !ok {
		return
	}

	if dur, err = self.adecodec.PacketDuration(inpkt.Data); err != nil {
		err = fmt.Errorf("transcode: PacketDuration() failed for input stream #%d", inpkt.Idx)
		return
	}

	if Debug {
		fmt.Println("transcode: push", inpkt.Time, dur)
	}
	self.timeline.Push(inpkt.Time, dur)

	var _outpkts [][]byte
	if _outpkts, err = self.aenc.Encode(frame); err != nil {
		return
	}
	for _, _outpkt := range _outpkts {
		if dur, err = self.aencodec.PacketDuration(_outpkt); err != nil {
			err = fmt.Errorf("transcode: PacketDuration() failed for output stream #%d", inpkt.Idx)
			return
		}
		outpkt := av.Packet{Idx: inpkt.Idx, Data: _outpkt}
		outpkt.Time = self.timeline.Pop(dur)

		if Debug {
			fmt.Println("transcode: pop", outpkt.Time, dur)
		}

		outpkts = append(outpkts, outpkt)
	}

	return
}

// Do the transcode.
// 
// In audio transcoding one Packet may transcode into many Packets
// packet time will be adjusted automatically.
func (self *Transcoder) Do(pkt av.Packet) (out []av.Packet, err error) {
	stream := self.streams[pkt.Idx]
	if stream.aenc != nil && stream.adec != nil {
		if out, err = stream.audioDecodeAndEncode(pkt); err != nil {
			return
		}
	} else {
		out = append(out, pkt)
	}
	return
}

// Get CodecDatas after transcoding.
func (self *Transcoder) Streams() (streams []av.CodecData, err error) {
	for _, stream := range self.streams {
		streams = append(streams, stream.codec)
	}
	return
}

// Close transcoder, close related encoder and decoders.
func (self *Transcoder) Close() (err error) {
	for _, stream := range self.streams {
		if stream.aenc != nil {
			stream.aenc.Close()
			stream.aenc = nil
		}
		if stream.adec != nil {
			stream.adec.Close()
			stream.adec = nil
		}
	}
	self.streams = nil
	return
}

// Wrap transcoder and origin Muxer into new Muxer.
// Write to new Muxer will do transcoding automatically.
type Muxer struct {
	av.Muxer // origin Muxer
	Options // transcode options
	transcoder *Transcoder
}

func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) {
	if self.transcoder, err = NewTranscoder(streams, self.Options); err != nil {
		return
	}
	var newstreams []av.CodecData
	if newstreams, err = self.transcoder.Streams(); err != nil {
		return
	}
	if err = self.Muxer.WriteHeader(newstreams); err != nil {
		return
	}
	return
}

func (self *Muxer) WritePacket(pkt av.Packet) (err error) {
	var outpkts []av.Packet
	if outpkts, err = self.transcoder.Do(pkt); err != nil {
		return
	}
	for _, pkt := range outpkts {
		if err = self.Muxer.WritePacket(pkt); err != nil {
			return
		}
	}
	return
}

func (self *Muxer) Close() (err error) {
	if self.transcoder != nil {
		return self.transcoder.Close()
	}
	return
}

// Wrap transcoder and origin Demuxer into new Demuxer.
// Read this Demuxer will do transcoding automatically.
type Demuxer struct {
	av.Demuxer
	Options
	transcoder *Transcoder
	outpkts []av.Packet
}

func (self *Demuxer) prepare() (err error) {
	if self.transcoder == nil {
		var streams []av.CodecData
		if streams, err = self.Demuxer.Streams(); err != nil {
			return
		}
		if self.transcoder, err = NewTranscoder(streams, self.Options); err != nil {
			return
		}
	}
	return
}

func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
	if err = self.prepare(); err != nil {
		return
	}
	for {
		if len(self.outpkts) > 0 {
			pkt = self.outpkts[0]
			self.outpkts = self.outpkts[1:]
			return
		}
		var rpkt av.Packet
		if rpkt, err = self.Demuxer.ReadPacket(); err != nil {
			return
		}
		if self.outpkts, err = self.transcoder.Do(rpkt); err != nil {
			return
		}
	}
	return
}

func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
	if err = self.prepare(); err != nil {
		return
	}
	return self.transcoder.Streams()
}

func (self *Demuxer) Close() (err error) {
	if self.transcoder != nil {
		return self.transcoder.Close()
	}
	return
}


================================================
FILE: cgo/ffmpeg/audio.go
================================================
package ffmpeg

/*
#include "ffmpeg.h"
int wrap_avcodec_decode_audio4(AVCodecContext *ctx, AVFrame *frame, void *data, int size, int *got) {
	struct AVPacket pkt = {.data = data, .size = size};
	return avcodec_decode_audio4(ctx, frame, got, &pkt);
}
int wrap_avresample_convert(AVAudioResampleContext *avr, int *out, int outsize, int outcount, int *in, int insize, int incount) {
	return avresample_convert(avr, (void *)out, outsize, outcount, (void *)in, insize, incount);
}
*/
import "C"
import (
	"unsafe"
	"runtime"
	"fmt"
	"time"
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/av/avutil"
	"github.com/nareix/joy4/codec/aacparser"
)

const debug = false

type Resampler struct {
	inSampleFormat, OutSampleFormat av.SampleFormat
	inChannelLayout, OutChannelLayout av.ChannelLayout
	inSampleRate, OutSampleRate int
	avr *C.AVAudioResampleContext
}

func (self *Resampler) Resample(in av.AudioFrame) (out av.AudioFrame, err error) {
	formatChange := in.SampleRate != self.inSampleRate || in.SampleFormat != self.inSampleFormat || in.ChannelLayout != self.inChannelLayout

	var flush av.AudioFrame

	if formatChange {
		if self.avr != nil {
			outChannels := self.OutChannelLayout.Count()
			if !self.OutSampleFormat.IsPlanar() {
				outChannels = 1
			}
			outData := make([]*C.uint8_t, outChannels)
			outSampleCount := int(C.avresample_get_out_samples(self.avr, C.int(in.SampleCount)))
			outLinesize := outSampleCount*self.OutSampleFormat.BytesPerSample()
			flush.Data = make([][]byte, outChannels)
			for i := 0; i < outChannels; i++ {
				flush.Data[i] = make([]byte, outLinesize)
				outData[i] = (*C.uint8_t)(unsafe.Pointer(&flush.Data[i][0]))
			}
			flush.ChannelLayout = self.OutChannelLayout
			flush.SampleFormat = self.OutSampleFormat
			flush.SampleRate = self.OutSampleRate

			convertSamples := int(C.wrap_avresample_convert(
				self.avr,
				(*C.int)(unsafe.Pointer(&outData[0])), C.int(outLinesize), C.int(outSampleCount),
				nil, C.int(0), C.int(0),
			))
			if convertSamples < 0 {
				err = fmt.Errorf("ffmpeg: avresample_convert_frame failed")
				return
			}
			flush.SampleCount = convertSamples
			if convertSamples < outSampleCount {
				for i := 0; i < outChannels; i++ {
					flush.Data[i] = flush.Data[i][:convertSamples*self.OutSampleFormat.BytesPerSample()]
				}
			}

			//fmt.Println("flush:", "outSampleCount", outSampleCount, "convertSamples", convertSamples, "datasize", len(flush.Data[0]))
		} else {
			runtime.SetFinalizer(self, func(self *Resampler) {
				self.Close()
			})
		}

		C.avresample_free(&self.avr)
		self.inSampleFormat = in.SampleFormat
		self.inSampleRate = in.SampleRate
		self.inChannelLayout = in.ChannelLayout
		avr := C.avresample_alloc_context()
		C.av_opt_set_int(unsafe.Pointer(avr), C.CString("in_channel_layout"), C.int64_t(channelLayoutAV2FF(self.inChannelLayout)), 0)
		C.av_opt_set_int(unsafe.Pointer(avr), C.CString("out_channel_layout"), C.int64_t(channelLayoutAV2FF(self.OutChannelLayout)), 0)
		C.av_opt_set_int(unsafe.Pointer(avr), C.CString("in_sample_rate"), C.int64_t(self.inSampleRate), 0)
		C.av_opt_set_int(unsafe.Pointer(avr), C.CString("out_sample_rate"), C.int64_t(self.OutSampleRate), 0)
		C.av_opt_set_int(unsafe.Pointer(avr), C.CString("in_sample_fmt"), C.int64_t(sampleFormatAV2FF(self.inSampleFormat)), 0)
		C.av_opt_set_int(unsafe.Pointer(avr), C.CString("out_sample_fmt"), C.int64_t(sampleFormatAV2FF(self.OutSampleFormat)), 0)
		C.avresample_open(avr)
		self.avr = avr
	}

	var inChannels, inLinesize int
	inSampleCount := in.SampleCount
	if !self.inSampleFormat.IsPlanar() {
		inChannels = 1
		inLinesize = inSampleCount*in.SampleFormat.BytesPerSample()*self.inChannelLayout.Count()
	} else {
		inChannels = self.inChannelLayout.Count()
		inLinesize = inSampleCount*in.SampleFormat.BytesPerSample()
	}
	inData := make([]*C.uint8_t, inChannels)
	for i := 0; i < inChannels; i++ {
		inData[i] = (*C.uint8_t)(unsafe.Pointer(&in.Data[i][0]))
	}

	var outChannels, outLinesize, outBytesPerSample int
	outSampleCount := int(C.avresample_get_out_samples(self.avr, C.int(in.SampleCount)))
	if !self.OutSampleFormat.IsPlanar() {
		outChannels = 1
		outBytesPerSample = self.OutSampleFormat.BytesPerSample()*self.OutChannelLayout.Count()
		outLinesize = outSampleCount*outBytesPerSample
	} else {
		outChannels = self.OutChannelLayout.Count()
		outBytesPerSample = self.OutSampleFormat.BytesPerSample()
		outLinesize = outSampleCount*outBytesPerSample
	}
	outData := make([]*C.uint8_t, outChannels)
	out.Data = make([][]byte, outChannels)
	for i := 0; i < outChannels; i++ {
		out.Data[i] = make([]byte, outLinesize)
		outData[i] = (*C.uint8_t)(unsafe.Pointer(&out.Data[i][0]))
	}
	out.ChannelLayout = self.OutChannelLayout
	out.SampleFormat = self.OutSampleFormat
	out.SampleRate = self.OutSampleRate

	convertSamples := int(C.wrap_avresample_convert(
		self.avr,
		(*C.int)(unsafe.Pointer(&outData[0])), C.int(outLinesize), C.int(outSampleCount),
		(*C.int)(unsafe.Pointer(&inData[0])), C.int(inLinesize), C.int(inSampleCount),
	))
	if convertSamples < 0 {
		err = fmt.Errorf("ffmpeg: avresample_convert_frame failed")
		return
	}

	out.SampleCount = convertSamples
	if convertSamples < outSampleCount {
		for i := 0; i < outChannels; i++ {
			out.Data[i] = out.Data[i][:convertSamples*outBytesPerSample]
		}
	}

	if flush.SampleCount > 0 {
		out = flush.Concat(out)
	}

	return
}

func (self *Resampler) Close() {
	C.avresample_free(&self.avr)
}

type AudioEncoder struct {
	ff *ffctx
	SampleRate int
	Bitrate int
	ChannelLayout av.ChannelLayout
	SampleFormat av.SampleFormat
	FrameSampleCount int
	framebuf av.AudioFrame
	codecData av.AudioCodecData
	resampler *Resampler
}

func sampleFormatAV2FF(sampleFormat av.SampleFormat) (ffsamplefmt int32) {
	switch sampleFormat {
	case av.U8:
		ffsamplefmt = C.AV_SAMPLE_FMT_U8
	case av.S16:
		ffsamplefmt = C.AV_SAMPLE_FMT_S16
	case av.S32:
		ffsamplefmt = C.AV_SAMPLE_FMT_S32
	case av.FLT:
		ffsamplefmt = C.AV_SAMPLE_FMT_FLT
	case av.DBL:
		ffsamplefmt = C.AV_SAMPLE_FMT_DBL
	case av.U8P:
		ffsamplefmt = C.AV_SAMPLE_FMT_U8P
	case av.S16P:
		ffsamplefmt = C.AV_SAMPLE_FMT_S16P
	case av.S32P:
		ffsamplefmt = C.AV_SAMPLE_FMT_S32P
	case av.FLTP:
		ffsamplefmt = C.AV_SAMPLE_FMT_FLTP
	case av.DBLP:
		ffsamplefmt = C.AV_SAMPLE_FMT_DBLP
	}
	return
}

func sampleFormatFF2AV(ffsamplefmt int32) (sampleFormat av.SampleFormat) {
	switch ffsamplefmt {
	case C.AV_SAMPLE_FMT_U8:          ///< unsigned 8 bits
		sampleFormat = av.U8
	case C.AV_SAMPLE_FMT_S16:         ///< signed 16 bits
		sampleFormat = av.S16
	case C.AV_SAMPLE_FMT_S32:         ///< signed 32 bits
		sampleFormat = av.S32
	case C.AV_SAMPLE_FMT_FLT:         ///< float
		sampleFormat = av.FLT
	case C.AV_SAMPLE_FMT_DBL:         ///< double
		sampleFormat = av.DBL
	case C.AV_SAMPLE_FMT_U8P:         ///< unsigned 8 bits, planar
		sampleFormat = av.U8P
	case C.AV_SAMPLE_FMT_S16P:        ///< signed 16 bits, planar
		sampleFormat = av.S16P
	case C.AV_SAMPLE_FMT_S32P:        ///< signed 32 bits, planar
		sampleFormat = av.S32P
	case C.AV_SAMPLE_FMT_FLTP:        ///< float, planar
		sampleFormat = av.FLTP
	case C.AV_SAMPLE_FMT_DBLP:        ///< double, planar
		sampleFormat = av.DBLP
	}
	return
}

func (self *AudioEncoder) SetSampleFormat(fmt av.SampleFormat) (err error) {
	self.SampleFormat = fmt
	return
}

func (self *AudioEncoder) SetSampleRate(rate int) (err error) {
	self.SampleRate = rate
	return
}

func (self *AudioEncoder) SetChannelLayout(ch av.ChannelLayout) (err error) {
	self.ChannelLayout = ch
	return
}

func (self *AudioEncoder) SetBitrate(bitrate int) (err error) {
	self.Bitrate = bitrate
	return
}

func (self *AudioEncoder) SetOption(key string, val interface{}) (err error) {
	ff := &self.ff.ff

	sval := fmt.Sprint(val)
	if key == "profile" {
		ff.profile = C.avcodec_profile_name_to_int(ff.codec, C.CString(sval))
		if ff.profile == C.FF_PROFILE_UNKNOWN {
			err = fmt.Errorf("ffmpeg: profile `%s` invalid", sval)
			return
		}
		return
	}

	C.av_dict_set(&ff.options, C.CString(key), C.CString(sval), 0)
	return
}

func (self *AudioEncoder) GetOption(key string, val interface{}) (err error) {
	ff := &self.ff.ff
	entry := C.av_dict_get(ff.options, C.CString(key), nil, 0)
	if entry == nil {
		err = fmt.Errorf("ffmpeg: GetOption failed: `%s` not exists", key)
		return
	}
	switch p := val.(type) {
	case *string:
		*p = C.GoString(entry.value)
	case *int:
		fmt.Sscanf(C.GoString(entry.value), "%d", p)
	default:
		err = fmt.Errorf("ffmpeg: GetOption failed: val must be *string or *int receiver")
		return
	}
	return
}

func (self *AudioEncoder) Setup() (err error) {
	ff := &self.ff.ff

	ff.frame = C.av_frame_alloc()

	if self.SampleFormat == av.SampleFormat(0) {
		self.SampleFormat = sampleFormatFF2AV(*ff.codec.sample_fmts)
	}

	//if self.Bitrate == 0 {
	//	self.Bitrate = 80000
	//}
	if self.SampleRate == 0 {
		self.SampleRate = 44100
	}
	if self.ChannelLayout == av.ChannelLayout(0) {
		self.ChannelLayout = av.CH_STEREO
	}

	ff.codecCtx.sample_fmt = sampleFormatAV2FF(self.SampleFormat)
	ff.codecCtx.sample_rate = C.int(self.SampleRate)
	ff.codecCtx.bit_rate = C.int64_t(self.Bitrate)
	ff.codecCtx.channel_layout = channelLayoutAV2FF(self.ChannelLayout)
	ff.codecCtx.strict_std_compliance = C.FF_COMPLIANCE_EXPERIMENTAL
	ff.codecCtx.flags = C.AV_CODEC_FLAG_GLOBAL_HEADER
	ff.codecCtx.profile = ff.profile

	if C.avcodec_open2(ff.codecCtx, ff.codec, nil) != 0 {
		err = fmt.Errorf("ffmpeg: encoder: avcodec_open2 failed")
		return
	}
	self.SampleFormat = sampleFormatFF2AV(ff.codecCtx.sample_fmt)
	self.FrameSampleCount = int(ff.codecCtx.frame_size)

	extradata := C.GoBytes(unsafe.Pointer(ff.codecCtx.extradata), ff.codecCtx.extradata_size)

	switch ff.codecCtx.codec_id {
	case C.AV_CODEC_ID_AAC:
		if self.codecData, err = aacparser.NewCodecDataFromMPEG4AudioConfigBytes(extradata); err != nil {
			return
		}

	default:
		self.codecData = audioCodecData{
			channelLayout: self.ChannelLayout,
			sampleFormat: self.SampleFormat,
			sampleRate: self.SampleRate,
			codecId: ff.codecCtx.codec_id,
			extradata: extradata,
		}
	}

	return
}

func (self *AudioEncoder) prepare() (err error) {
	ff := &self.ff.ff

	if ff.frame == nil {
		if err = self.Setup(); err != nil {
			return
		}
	}

	return
}

func (self *AudioEncoder) CodecData() (codec av.AudioCodecData, err error) {
	if err = self.prepare(); err != nil {
		return
	}
	codec = self.codecData
	return
}

func (self *AudioEncoder) encodeOne(frame av.AudioFrame) (gotpkt bool, pkt []byte, err error) {
	if err = self.prepare(); err != nil {
		return
	}

	ff := &self.ff.ff

	cpkt := C.AVPacket{}
	cgotpkt := C.int(0)
	audioFrameAssignToFF(frame, ff.frame)

	if false {
		farr := []string{}
		for i := 0; i < len(frame.Data[0])/4; i++ {
			var f *float64 = (*float64)(unsafe.Pointer(&frame.Data[0][i*4]))
			farr = append(farr, fmt.Sprintf("%.8f", *f))
		}
		fmt.Println(farr)
	}
	cerr := C.avcodec_encode_audio2(ff.codecCtx, &cpkt, ff.frame, &cgotpkt)
	if cerr < C.int(0) {
		err = fmt.Errorf("ffmpeg: avcodec_encode_audio2 failed: %d", cerr)
		return
	}

	if cgotpkt != 0 {
		gotpkt = true
		pkt = C.GoBytes(unsafe.Pointer(cpkt.data), cpkt.size)
		C.av_packet_unref(&cpkt)

		if debug {
			fmt.Println("ffmpeg: Encode", frame.SampleCount, frame.SampleRate, frame.ChannelLayout, frame.SampleFormat, "len", len(pkt))
		}
	}

	return
}

func (self *AudioEncoder) resample(in av.AudioFrame) (out av.AudioFrame, err error) {
	if self.resampler == nil {
		self.resampler = &Resampler{
			OutSampleFormat: self.SampleFormat,
			OutSampleRate: self.SampleRate,
			OutChannelLayout: self.ChannelLayout,
		}
	}
	if out, err = self.resampler.Resample(in); err != nil {
		return
	}
	return
}

func (self *AudioEncoder) Encode(frame av.AudioFrame) (pkts [][]byte, err error) {
	var gotpkt bool
	var pkt []byte

	if frame.SampleFormat != self.SampleFormat || frame.ChannelLayout != self.ChannelLayout || frame.SampleRate != self.SampleRate {
		if frame, err = self.resample(frame); err != nil {
			return
		}
	}

	if self.FrameSampleCount != 0 {
		if self.framebuf.SampleCount == 0 {
			self.framebuf = frame
		} else {
			self.framebuf = self.framebuf.Concat(frame)
		}
		for self.framebuf.SampleCount >= self.FrameSampleCount {
			frame := self.framebuf.Slice(0, self.FrameSampleCount)
			if gotpkt, pkt, err = self.encodeOne(frame); err != nil {
				return
			}
			if gotpkt {
				pkts = append(pkts, pkt)
			}
			self.framebuf = self.framebuf.Slice(self.FrameSampleCount, self.framebuf.SampleCount)
		}
	} else {
		if gotpkt, pkt, err = self.encodeOne(frame); err != nil {
			return
		}
		if gotpkt {
			pkts = append(pkts, pkt)
		}
	}

	return
}

func (self *AudioEncoder) Close() {
	freeFFCtx(self.ff)
	if self.resampler != nil {
		self.resampler.Close()
		self.resampler = nil
	}
}

func audioFrameAssignToAVParams(f *C.AVFrame, frame *av.AudioFrame) {
	frame.SampleFormat = sampleFormatFF2AV(int32(f.format))
	frame.ChannelLayout = channelLayoutFF2AV(f.channel_layout)
	frame.SampleRate = int(f.sample_rate)
}

func audioFrameAssignToAVData(f *C.AVFrame, frame *av.AudioFrame) {
	frame.SampleCount = int(f.nb_samples)
	frame.Data = make([][]byte, int(f.channels))
	for i := 0; i < int(f.channels); i++ {
		frame.Data[i] = C.GoBytes(unsafe.Pointer(f.data[i]), f.linesize[0])
	}
}

func audioFrameAssignToAV(f *C.AVFrame, frame *av.AudioFrame) {
	audioFrameAssignToAVParams(f, frame)
	audioFrameAssignToAVData(f, frame)
}

func audioFrameAssignToFFParams(frame av.AudioFrame, f *C.AVFrame) {
	f.format = C.int(sampleFormatAV2FF(frame.SampleFormat))
	f.channel_layout = channelLayoutAV2FF(frame.ChannelLayout)
	f.sample_rate = C.int(frame.SampleRate)
	f.channels = C.int(frame.ChannelLayout.Count())
}

func audioFrameAssignToFFData(frame av.AudioFrame, f *C.AVFrame) {
	f.nb_samples = C.int(frame.SampleCount)
	for i := range frame.Data {
		f.data[i] = (*C.uint8_t)(unsafe.Pointer(&frame.Data[i][0]))
		f.linesize[i] = C.int(len(frame.Data[i]))
	}
}

func audioFrameAssignToFF(frame av.AudioFrame, f *C.AVFrame) {
	audioFrameAssignToFFParams(frame, f)
	audioFrameAssignToFFData(frame, f)
}

func channelLayoutFF2AV(layout C.uint64_t) (channelLayout av.ChannelLayout) {
	if layout & C.AV_CH_FRONT_CENTER != 0 {
		channelLayout |= av.CH_FRONT_CENTER
	}
	if layout & C.AV_CH_FRONT_LEFT != 0 {
		channelLayout |= av.CH_FRONT_LEFT
	}
	if layout & C.AV_CH_FRONT_RIGHT != 0 {
		channelLayout |= av.CH_FRONT_RIGHT
	}
	if layout & C.AV_CH_BACK_CENTER != 0 {
		channelLayout |= av.CH_BACK_CENTER
	}
	if layout & C.AV_CH_BACK_LEFT != 0 {
		channelLayout |= av.CH_BACK_LEFT
	}
	if layout & C.AV_CH_BACK_RIGHT != 0 {
		channelLayout |= av.CH_BACK_RIGHT
	}
	if layout & C.AV_CH_SIDE_LEFT != 0 {
		channelLayout |= av.CH_SIDE_LEFT
	}
	if layout & C.AV_CH_SIDE_RIGHT != 0 {
		channelLayout |= av.CH_SIDE_RIGHT
	}
	if layout & C.AV_CH_LOW_FREQUENCY != 0 {
		channelLayout |= av.CH_LOW_FREQ
	}
	return
}

func channelLayoutAV2FF(channelLayout av.ChannelLayout) (layout C.uint64_t) {
	if channelLayout & av.CH_FRONT_CENTER != 0 {
		layout |= C.AV_CH_FRONT_CENTER
	}
	if channelLayout & av.CH_FRONT_LEFT != 0 {
		layout |= C.AV_CH_FRONT_LEFT
	}
	if channelLayout & av.CH_FRONT_RIGHT != 0 {
		layout |= C.AV_CH_FRONT_RIGHT
	}
	if channelLayout & av.CH_BACK_CENTER != 0 {
		layout |= C.AV_CH_BACK_CENTER
	}
	if channelLayout & av.CH_BACK_LEFT != 0 {
		layout |= C.AV_CH_BACK_LEFT
	}
	if channelLayout & av.CH_BACK_RIGHT != 0 {
		layout |= C.AV_CH_BACK_RIGHT
	}
	if channelLayout & av.CH_SIDE_LEFT != 0 {
		layout |= C.AV_CH_SIDE_LEFT
	}
	if channelLayout & av.CH_SIDE_RIGHT != 0 {
		layout |= C.AV_CH_SIDE_RIGHT
	}
	if channelLayout & av.CH_LOW_FREQ != 0 {
		layout |= C.AV_CH_LOW_FREQUENCY
	}
	return
}

type AudioDecoder struct {
	ff *ffctx
	ChannelLayout av.ChannelLayout
	SampleFormat av.SampleFormat
	SampleRate int
	Extradata []byte
}

func (self *AudioDecoder) Setup() (err error) {
	ff := &self.ff.ff

	ff.frame = C.av_frame_alloc()

	if len(self.Extradata) > 0 {
		ff.codecCtx.extradata = (*C.uint8_t)(unsafe.Pointer(&self.Extradata[0]))
		ff.codecCtx.extradata_size = C.int(len(self.Extradata))
	}
	if debug {
		fmt.Println("ffmpeg: Decoder.Setup Extradata.len", len(self.Extradata))
	}

	ff.codecCtx.sample_rate = C.int(self.SampleRate)
	ff.codecCtx.channel_layout = channelLayoutAV2FF(self.ChannelLayout)
	ff.codecCtx.channels = C.int(self.ChannelLayout.Count())
	if C.avcodec_open2(ff.codecCtx, ff.codec, nil) != 0 {
		err = fmt.Errorf("ffmpeg: decoder: avcodec_open2 failed")
		return
	}
	self.SampleFormat = sampleFormatFF2AV(ff.codecCtx.sample_fmt)
	self.ChannelLayout = channelLayoutFF2AV(ff.codecCtx.channel_layout)
	if self.SampleRate == 0 {
		self.SampleRate = int(ff.codecCtx.sample_rate)
	}

	return
}

func (self *AudioDecoder) Decode(pkt []byte) (gotframe bool, frame av.AudioFrame, err error) {
	ff := &self.ff.ff

	cgotframe := C.int(0)
	cerr := C.wrap_avcodec_decode_audio4(ff.codecCtx, ff.frame, unsafe.Pointer(&pkt[0]), C.int(len(pkt)), &cgotframe)
	if cerr < C.int(0) {
		err = fmt.Errorf("ffmpeg: avcodec_decode_audio4 failed: %d", cerr)
		return
	}

	if cgotframe != C.int(0) {
		gotframe = true
		audioFrameAssignToAV(ff.frame, &frame)
		frame.SampleRate = self.SampleRate

		if debug {
			fmt.Println("ffmpeg: Decode", frame.SampleCount, frame.SampleRate, frame.ChannelLayout, frame.SampleFormat)
		}
	}

	return
}

func (self *AudioDecoder) Close() {
	freeFFCtx(self.ff)
}

func NewAudioEncoderByCodecType(typ av.CodecType) (enc *AudioEncoder, err error) {
	var id uint32

	switch typ {
	case av.AAC:
		id = C.AV_CODEC_ID_AAC

	default:
		err = fmt.Errorf("ffmpeg: cannot find encoder codecType=%d", typ)
		return
	}

	codec := C.avcodec_find_encoder(id)
	if codec == nil || C.avcodec_get_type(id) != C.AVMEDIA_TYPE_AUDIO {
		err = fmt.Errorf("ffmpeg: cannot find audio encoder codecId=%d", id)
		return
	}

	_enc := &AudioEncoder{}
	if _enc.ff, err = newFFCtxByCodec(codec); err != nil {
		return
	}
	enc = _enc
	return
}

func NewAudioEncoderByName(name string) (enc *AudioEncoder, err error) {
	_enc := &AudioEncoder{}

	codec := C.avcodec_find_encoder_by_name(C.CString(name))
	if codec == nil || C.avcodec_get_type(codec.id) != C.AVMEDIA_TYPE_AUDIO {
		err = fmt.Errorf("ffmpeg: cannot find audio encoder name=%s", name)
		return
	}

	if _enc.ff, err = newFFCtxByCodec(codec); err != nil {
		return
	}
	enc = _enc
	return
}

func NewAudioDecoder(codec av.AudioCodecData) (dec *AudioDecoder, err error) {
	_dec := &AudioDecoder{}
	var id uint32

	switch codec.Type() {
	case av.AAC:
		if aaccodec, ok := codec.(aacparser.CodecData); ok {
			_dec.Extradata = aaccodec.MPEG4AudioConfigBytes()
			id = C.AV_CODEC_ID_AAC
		} else {
			err = fmt.Errorf("ffmpeg: aac CodecData must be aacparser.CodecData")
			return
		}

	case av.SPEEX:
		id = C.AV_CODEC_ID_SPEEX

	case av.PCM_MULAW:
		id = C.AV_CODEC_ID_PCM_MULAW

	case av.PCM_ALAW:
		id = C.AV_CODEC_ID_PCM_ALAW

	default:
		if ffcodec, ok := codec.(audioCodecData); ok {
			_dec.Extradata = ffcodec.extradata
			id = ffcodec.codecId
		} else {
			err = fmt.Errorf("ffmpeg: invalid CodecData for ffmpeg to decode")
			return
		}
	}

	c := C.avcodec_find_decoder(id)
	if c == nil || C.avcodec_get_type(c.id) != C.AVMEDIA_TYPE_AUDIO {
		err = fmt.Errorf("ffmpeg: cannot find audio decoder id=%d", id)
		return
	}

	if _dec.ff, err = newFFCtxByCodec(c); err != nil {
		return
	}

	_dec.SampleFormat = codec.SampleFormat()
	_dec.SampleRate = codec.SampleRate()
	_dec.ChannelLayout = codec.ChannelLayout()
	if err = _dec.Setup(); err != nil {
		return
	}

	dec = _dec
	return
}

type audioCodecData struct {
	codecId uint32
	sampleFormat av.SampleFormat
	channelLayout av.ChannelLayout
	sampleRate int
	extradata []byte
}

func (self audioCodecData) Type() av.CodecType {
	return av.MakeAudioCodecType(self.codecId)
}

func (self audioCodecData) SampleRate() int {
	return self.sampleRate
}

func (self audioCodecData) SampleFormat() av.SampleFormat {
	return self.sampleFormat
}

func (self audioCodecData) ChannelLayout() av.ChannelLayout {
	return self.channelLayout
}

func (self audioCodecData) PacketDuration(data []byte) (dur time.Duration, err error) {
	// TODO: implement it: ffmpeg get_audio_frame_duration
	err = fmt.Errorf("ffmpeg: cannot get packet duration")
	return
}

func AudioCodecHandler(h *avutil.RegisterHandler) {
	h.AudioDecoder = func(codec av.AudioCodecData) (av.AudioDecoder, error) {
		if dec, err := NewAudioDecoder(codec); err != nil {
			return nil, nil
		} else {
			return dec, err
		}
	}

	h.AudioEncoder = func(typ av.CodecType) (av.AudioEncoder, error) {
		if enc, err := NewAudioEncoderByCodecType(typ); err != nil {
			return nil, nil
		} else {
			return enc, err
		}
	}
}



================================================
FILE: cgo/ffmpeg/ffmpeg.go
================================================
package ffmpeg

/*
#cgo LDFLAGS: -lavformat -lavutil -lavcodec -lavresample -lswscale
#include "ffmpeg.h"
void ffinit() {
	av_register_all();
}
*/
import "C"
import (
	"runtime"
	"unsafe"
)

const (
	QUIET = int(C.AV_LOG_QUIET)
	PANIC = int(C.AV_LOG_PANIC)
	FATAL = int(C.AV_LOG_FATAL)
	ERROR = int(C.AV_LOG_ERROR)
	WARNING = int(C.AV_LOG_WARNING)
	INFO = int(C.AV_LOG_INFO)
	VERBOSE = int(C.AV_LOG_VERBOSE)
	DEBUG = int(C.AV_LOG_DEBUG)
	TRACE = int(C.AV_LOG_TRACE)
)

func HasEncoder(name string) bool {
	return C.avcodec_find_encoder_by_name(C.CString(name)) != nil
}

func HasDecoder(name string) bool {
	return C.avcodec_find_decoder_by_name(C.CString(name)) != nil
}

//func EncodersList() []string
//func DecodersList() []string

func SetLogLevel(level int) {
	C.av_log_set_level(C.int(level))
}

func init() {
	C.ffinit()
}

type ffctx struct {
	ff C.FFCtx
}

func newFFCtxByCodec(codec *C.AVCodec) (ff *ffctx, err error) {
	ff = &ffctx{}
	ff.ff.codec = codec
	ff.ff.codecCtx = C.avcodec_alloc_context3(codec)
	ff.ff.profile = C.FF_PROFILE_UNKNOWN
	runtime.SetFinalizer(ff, freeFFCtx)
	return
}

func freeFFCtx(self *ffctx) {
	ff := &self.ff
	if ff.frame != nil {
		C.av_frame_free(&ff.frame)
	}
	if ff.codecCtx != nil {
		C.avcodec_close(ff.codecCtx)
		C.av_free(unsafe.Pointer(ff.codecCtx))
		ff.codecCtx = nil
	}
	if ff.options != nil {
		C.av_dict_free(&ff.options)
	}
}



================================================
FILE: cgo/ffmpeg/ffmpeg.h
================================================

#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavresample/avresample.h>
#include <libavutil/opt.h>
#include <string.h>
#include <libswscale/swscale.h>

typedef struct {
	AVCodec *codec;
	AVCodecContext *codecCtx;
	AVFrame *frame;
	AVDictionary *options;
	int profile;
} FFCtx;

static inline int avcodec_profile_name_to_int(AVCodec *codec, const char *name) {
	const AVProfile *p;
	for (p = codec->profiles; p != NULL && p->profile != FF_PROFILE_UNKNOWN; p++)
		if (!strcasecmp(p->name, name))
			return p->profile;
	return FF_PROFILE_UNKNOWN;
}



================================================
FILE: cgo/ffmpeg/video.go
================================================
package ffmpeg

/*
#include "ffmpeg.h"
int wrap_avcodec_decode_video2(AVCodecContext *ctx, AVFrame *frame, void *data, int size, int *got) {
	struct AVPacket pkt = {.data = data, .size = size};
	return avcodec_decode_video2(ctx, frame, got, &pkt);
}
*/
import "C"
import (
	"unsafe"
	"runtime"
	"fmt"
	"image"
	"reflect"
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/codec/h264parser"
)

type VideoDecoder struct {
	ff *ffctx
	Extradata []byte
}

func (self *VideoDecoder) Setup() (err error) {
	ff := &self.ff.ff
	if len(self.Extradata) > 0 {
		ff.codecCtx.extradata = (*C.uint8_t)(unsafe.Pointer(&self.Extradata[0]))
		ff.codecCtx.extradata_size = C.int(len(self.Extradata))
	}
	if C.avcodec_open2(ff.codecCtx, ff.codec, nil) != 0 {
		err = fmt.Errorf("ffmpeg: decoder: avcodec_open2 failed")
		return
	}
	return
}

func fromCPtr(buf unsafe.Pointer, size int) (ret []uint8) {
	hdr := (*reflect.SliceHeader)((unsafe.Pointer(&ret)))
	hdr.Cap = size
	hdr.Len = size
	hdr.Data = uintptr(buf)
	return
}

type VideoFrame struct {
	Image image.YCbCr
	frame *C.AVFrame
}

func (self *VideoFrame) Free() {
	self.Image = image.YCbCr{}
	C.av_frame_free(&self.frame)
}

func freeVideoFrame(self *VideoFrame) {
	self.Free()
}

func (self *VideoDecoder) Decode(pkt []byte) (img *VideoFrame, err error) {
	ff := &self.ff.ff

	cgotimg := C.int(0)
	frame := C.av_frame_alloc()
	cerr := C.wrap_avcodec_decode_video2(ff.codecCtx, frame, unsafe.Pointer(&pkt[0]), C.int(len(pkt)), &cgotimg)
	if cerr < C.int(0) {
		err = fmt.Errorf("ffmpeg: avcodec_decode_video2 failed: %d", cerr)
		return
	}

	if cgotimg != C.int(0) {
		w := int(frame.width)
		h := int(frame.height)
		ys := int(frame.linesize[0])
		cs := int(frame.linesize[1])

		img = &VideoFrame{Image: image.YCbCr{
			Y: fromCPtr(unsafe.Pointer(frame.data[0]), ys*h),
			Cb: fromCPtr(unsafe.Pointer(frame.data[1]), cs*h/2),
			Cr: fromCPtr(unsafe.Pointer(frame.data[2]), cs*h/2),
			YStride: ys,
			CStride: cs,
			SubsampleRatio: image.YCbCrSubsampleRatio420,
			Rect: image.Rect(0, 0, w, h),
		}, frame: frame}
		runtime.SetFinalizer(img, freeVideoFrame)
	}

	return
}

func NewVideoDecoder(stream av.CodecData) (dec *VideoDecoder, err error) {
	_dec := &VideoDecoder{}
	var id uint32

	switch stream.Type() {
	case av.H264:
		h264 := stream.(h264parser.CodecData)
		_dec.Extradata = h264.AVCDecoderConfRecordBytes()
		id = C.AV_CODEC_ID_H264

	default:
		err = fmt.Errorf("ffmpeg: NewVideoDecoder codec=%v unsupported", stream.Type())
		return
	}

	c := C.avcodec_find_decoder(id)
	if c == nil || C.avcodec_get_type(id) != C.AVMEDIA_TYPE_VIDEO {
		err = fmt.Errorf("ffmpeg: cannot find video decoder codecId=%d", id)
		return
	}

	if _dec.ff, err = newFFCtxByCodec(c); err != nil {
		return
	}
	if err =  _dec.Setup(); err != nil {
		return
	}

	dec = _dec
	return
}



================================================
FILE: codec/aacparser/parser.go
================================================
package aacparser

import (
	"github.com/nareix/joy4/utils/bits"
	"github.com/nareix/joy4/av"
	"time"
	"fmt"
	"bytes"
	"io"
)

// copied from libavcodec/mpeg4audio.h
const (
	AOT_AAC_MAIN        = 1 + iota  ///< Y                       Main
	AOT_AAC_LC                      ///< Y                       Low Complexity
	AOT_AAC_SSR                     ///< N (code in SoC repo)    Scalable Sample Rate
	AOT_AAC_LTP                     ///< Y                       Long Term Prediction
	AOT_SBR                         ///< Y                       Spectral Band Replication
	AOT_AAC_SCALABLE                ///< N                       Scalable
	AOT_TWINVQ                      ///< N                       Twin Vector Quantizer
	AOT_CELP                        ///< N                       Code Excited Linear Prediction
	AOT_HVXC                        ///< N                       Harmonic Vector eXcitation Coding
	AOT_TTSI            = 12 + iota ///< N                       Text-To-Speech Interface
	AOT_MAINSYNTH                   ///< N                       Main Synthesis
	AOT_WAVESYNTH                   ///< N                       Wavetable Synthesis
	AOT_MIDI                        ///< N                       General MIDI
	AOT_SAFX                        ///< N                       Algorithmic Synthesis and Audio Effects
	AOT_ER_AAC_LC                   ///< N                       Error Resilient Low Complexity
	AOT_ER_AAC_LTP      = 19 + iota ///< N                       Error Resilient Long Term Prediction
	AOT_ER_AAC_SCALABLE             ///< N                       Error Resilient Scalable
	AOT_ER_TWINVQ                   ///< N                       Error Resilient Twin Vector Quantizer
	AOT_ER_BSAC                     ///< N                       Error Resilient Bit-Sliced Arithmetic Coding
	AOT_ER_AAC_LD                   ///< N                       Error Resilient Low Delay
	AOT_ER_CELP                     ///< N                       Error Resilient Code Excited Linear Prediction
	AOT_ER_HVXC                     ///< N                       Error Resilient Harmonic Vector eXcitation Coding
	AOT_ER_HILN                     ///< N                       Error Resilient Harmonic and Individual Lines plus Noise
	AOT_ER_PARAM                    ///< N                       Error Resilient Parametric
	AOT_SSC                         ///< N                       SinuSoidal Coding
	AOT_PS                          ///< N                       Parametric Stereo
	AOT_SURROUND                    ///< N                       MPEG Surround
	AOT_ESCAPE                      ///< Y                       Escape Value
	AOT_L1                          ///< Y                       Layer 1
	AOT_L2                          ///< Y                       Layer 2
	AOT_L3                          ///< Y                       Layer 3
	AOT_DST                         ///< N                       Direct Stream Transfer
	AOT_ALS                         ///< Y                       Audio LosslesS
	AOT_SLS                         ///< N                       Scalable LosslesS
	AOT_SLS_NON_CORE                ///< N                       Scalable LosslesS (non core)
	AOT_ER_AAC_ELD                  ///< N                       Error Resilient Enhanced Low Delay
	AOT_SMR_SIMPLE                  ///< N                       Symbolic Music Representation Simple
	AOT_SMR_MAIN                    ///< N                       Symbolic Music Representation Main
	AOT_USAC_NOSBR                  ///< N                       Unified Speech and Audio Coding (no SBR)
	AOT_SAOC                        ///< N                       Spatial Audio Object Coding
	AOT_LD_SURROUND                 ///< N                       Low Delay MPEG Surround
	AOT_USAC                        ///< N                       Unified Speech and Audio Coding
)

type MPEG4AudioConfig struct {
	SampleRate      int
	ChannelLayout   av.ChannelLayout
	ObjectType      uint
	SampleRateIndex uint
	ChannelConfig   uint
}

var sampleRateTable = []int{
	96000, 88200, 64000, 48000, 44100, 32000,
	24000, 22050, 16000, 12000, 11025, 8000, 7350,
}

/*
These are the channel configurations:
0: Defined in AOT Specifc Config
1: 1 channel: front-center
2: 2 channels: front-left, front-right
3: 3 channels: front-center, front-left, front-right
4: 4 channels: front-center, front-left, front-right, back-center
5: 5 channels: front-center, front-left, front-right, back-left, back-right
6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
8-15: Reserved
*/
var chanConfigTable = []av.ChannelLayout{
	0,
	av.CH_FRONT_CENTER,
	av.CH_FRONT_LEFT|av.CH_FRONT_RIGHT,
	av.CH_FRONT_CENTER|av.CH_FRONT_LEFT|av.CH_FRONT_RIGHT,
	av.CH_FRONT_CENTER|av.CH_FRONT_LEFT|av.CH_FRONT_RIGHT|av.CH_BACK_CENTER,
	av.CH_FRONT_CENTER|av.CH_FRONT_LEFT|av.CH_FRONT_RIGHT|av.CH_BACK_LEFT|av.CH_BACK_RIGHT,
	av.CH_FRONT_CENTER|av.CH_FRONT_LEFT|av.CH_FRONT_RIGHT|av.CH_BACK_LEFT|av.CH_BACK_RIGHT|av.CH_LOW_FREQ,
	av.CH_FRONT_CENTER|av.CH_FRONT_LEFT|av.CH_FRONT_RIGHT|av.CH_SIDE_LEFT|av.CH_SIDE_RIGHT|av.CH_BACK_LEFT|av.CH_BACK_RIGHT|av.CH_LOW_FREQ,
}

func ParseADTSHeader(frame []byte) (config MPEG4AudioConfig, hdrlen int, framelen int, samples int, err error) {
	if frame[0] != 0xff || frame[1]&0xf6 != 0xf0 {
		err = fmt.Errorf("aacparser: not adts header")
		return
	}
	config.ObjectType = uint(frame[2]>>6) + 1
	config.SampleRateIndex = uint(frame[2] >> 2 & 0xf)
	config.ChannelConfig = uint(frame[2]<<2&0x4 | frame[3]>>6&0x3)
	if config.ChannelConfig == uint(0) {
		err = fmt.Errorf("aacparser: adts channel count invalid")
		return
	}
	(&config).Complete()
	framelen = int(frame[3]&0x3)<<11 | int(frame[4])<<3 | int(frame[5]>>5)
	samples = (int(frame[6]&0x3) + 1) * 1024
	hdrlen = 7
	if frame[1]&0x1 == 0 {
		hdrlen = 9
	}
	if framelen < hdrlen {
		err = fmt.Errorf("aacparser: adts framelen < hdrlen")
		return
	}
	return
}

const ADTSHeaderLength = 7

func FillADTSHeader(header []byte, config MPEG4AudioConfig, samples int, payloadLength int) {
	payloadLength += 7
	//AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM MMMMMMMM MMMOOOOO OOOOOOPP (QQQQQQQQ QQQQQQQQ)
	header[0] = 0xff
	header[1] = 0xf1
	header[2] = 0x50
	header[3] = 0x80
	header[4] = 0x43
	header[5] = 0xff
	header[6] = 0xcd
	//config.ObjectType = uint(frames[2]>>6)+1
	//config.SampleRateIndex = uint(frames[2]>>2&0xf)
	//config.ChannelConfig = uint(frames[2]<<2&0x4|frames[3]>>6&0x3)
	header[2] = (byte(config.ObjectType-1)&0x3)<<6 | (byte(config.SampleRateIndex)&0xf)<<2 | byte(config.ChannelConfig>>2)&0x1
	header[3] = header[3]&0x3f | byte(config.ChannelConfig&0x3)<<6
	header[3] = header[3]&0xfc | byte(payloadLength>>11)&0x3
	header[4] = byte(payloadLength >> 3)
	header[5] = header[5]&0x1f | (byte(payloadLength)&0x7)<<5
	header[6] = header[6]&0xfc | byte(samples/1024-1)
	return
}

func readObjectType(r *bits.Reader) (objectType uint, err error) {
	if objectType, err = r.ReadBits(5); err != nil {
		return
	}
	if objectType == AOT_ESCAPE {
		var i uint
		if i, err = r.ReadBits(6); err != nil {
			return
		}
		objectType = 32 + i
	}
	return
}

func writeObjectType(w *bits.Writer, objectType uint) (err error) {
	if objectType >= 32 {
		if err = w.WriteBits(AOT_ESCAPE, 5); err != nil {
			return
		}
		if err = w.WriteBits(objectType-32, 6); err != nil {
			return
		}
	} else {
		if err = w.WriteBits(objectType, 5); err != nil {
			return
		}
	}
	return
}

func readSampleRateIndex(r *bits.Reader) (index uint, err error) {
	if index, err = r.ReadBits(4); err != nil {
		return
	}
	if index == 0xf {
		if index, err = r.ReadBits(24); err != nil {
			return
		}
	}
	return
}

func writeSampleRateIndex(w *bits.Writer, index uint) (err error) {
	if index >= 0xf {
		if err = w.WriteBits(0xf, 4); err != nil {
			return
		}
		if err = w.WriteBits(index, 24); err != nil {
			return
		}
	} else {
		if err = w.WriteBits(index, 4); err != nil {
			return
		}
	}
	return
}

func (self MPEG4AudioConfig) IsValid() bool {
	return self.ObjectType > 0
}

func (self *MPEG4AudioConfig) Complete() {
	if int(self.SampleRateIndex) < len(sampleRateTable) {
		self.SampleRate = sampleRateTable[self.SampleRateIndex]
	}
	if int(self.ChannelConfig) < len(chanConfigTable) {
		self.ChannelLayout = chanConfigTable[self.ChannelConfig]
	}
	return
}

func ParseMPEG4AudioConfigBytes(data []byte) (config MPEG4AudioConfig, err error) {
	// copied from libavcodec/mpeg4audio.c avpriv_mpeg4audio_get_config()
	r := bytes.NewReader(data)
	br := &bits.Reader{R: r}
	if config.ObjectType, err = readObjectType(br); err != nil {
		return
	}
	if config.SampleRateIndex, err = readSampleRateIndex(br); err != nil {
		return
	}
	if config.ChannelConfig, err = br.ReadBits(4); err != nil {
		return
	}
	(&config).Complete()
	return
}

func WriteMPEG4AudioConfig(w io.Writer, config MPEG4AudioConfig) (err error) {
	bw := &bits.Writer{W: w}
	if err = writeObjectType(bw, config.ObjectType); err != nil {
		return
	}

	if config.SampleRateIndex == 0 {
		for i, rate := range sampleRateTable {
			if rate == config.SampleRate {
				config.SampleRateIndex = uint(i)
			}
		}
	}
	if err = writeSampleRateIndex(bw, config.SampleRateIndex); err != nil {
		return
	}

	if config.ChannelConfig == 0 {
		for i, layout := range chanConfigTable {
			if layout == config.ChannelLayout {
				config.ChannelConfig = uint(i)
			}
		}
	}
	if err = bw.WriteBits(config.ChannelConfig, 4); err != nil {
		return
	}

	if err = bw.FlushBits(); err != nil {
		return
	}
	return
}

type CodecData struct {
	ConfigBytes []byte
	Config MPEG4AudioConfig
}

func (self CodecData) Type() av.CodecType {
	return av.AAC
}

func (self CodecData) MPEG4AudioConfigBytes() []byte {
	return self.ConfigBytes
}

func (self CodecData) ChannelLayout() av.ChannelLayout {
	return self.Config.ChannelLayout
}

func (self CodecData) SampleRate() int {
	return self.Config.SampleRate
}

func (self CodecData) SampleFormat() av.SampleFormat {
	return av.FLTP
}

func (self CodecData) PacketDuration(data []byte) (dur time.Duration, err error) {
	dur = time.Duration(1024) * time.Second / time.Duration(self.Config.SampleRate)
	return
}

func NewCodecDataFromMPEG4AudioConfig(config MPEG4AudioConfig) (self CodecData, err error) {
	b := &bytes.Buffer{}
	WriteMPEG4AudioConfig(b, config)
	return NewCodecDataFromMPEG4AudioConfigBytes(b.Bytes())
}

func NewCodecDataFromMPEG4AudioConfigBytes(config []byte) (self CodecData, err error) {
	self.ConfigBytes = config
	if self.Config, err = ParseMPEG4AudioConfigBytes(config); err != nil {
		err = fmt.Errorf("aacparser: parse MPEG4AudioConfig failed(%s)", err)
		return
	}
	return
}



================================================
FILE: codec/codec.go
================================================
package codec

import (
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/codec/fake"
	"time"
)

type PCMUCodecData struct {
	typ av.CodecType
}

func (self PCMUCodecData) Type() av.CodecType {
	return self.typ
}

func (self PCMUCodecData) SampleRate() int {
	return 8000
}

func (self PCMUCodecData) ChannelLayout() av.ChannelLayout {
	return av.CH_MONO
}

func (self PCMUCodecData) SampleFormat() av.SampleFormat {
	return av.S16
}

func (self PCMUCodecData) PacketDuration(data []byte) (time.Duration, error) {
	return time.Duration(len(data)) * time.Second / time.Duration(8000), nil
}

func NewPCMMulawCodecData() av.AudioCodecData {
	return PCMUCodecData{
		typ: av.PCM_MULAW,
	}
}

func NewPCMAlawCodecData() av.AudioCodecData {
	return PCMUCodecData{
		typ: av.PCM_ALAW,
	}
}

type SpeexCodecData struct {
	fake.CodecData
}

func (self SpeexCodecData) PacketDuration(data []byte) (time.Duration, error) {
	// libavcodec/libspeexdec.c
	// samples = samplerate/50
	// duration = 0.02s
	return time.Millisecond*20, nil
}

func NewSpeexCodecData(sr int, cl av.ChannelLayout) SpeexCodecData {
	codec := SpeexCodecData{}
	codec.CodecType_ = av.SPEEX
	codec.SampleFormat_ = av.S16
	codec.SampleRate_ = sr
	codec.ChannelLayout_ = cl
	return codec
}



================================================
FILE: codec/fake/fake.go
================================================
package fake

import (
	"github.com/nareix/joy4/av"
)

type CodecData struct {
	CodecType_ av.CodecType
	SampleRate_ int
	SampleFormat_ av.SampleFormat
	ChannelLayout_ av.ChannelLayout
}

func (self CodecData) Type() av.CodecType {
	return self.CodecType_
}

func (self CodecData) SampleFormat() av.SampleFormat {
	return self.SampleFormat_
}

func (self CodecData) ChannelLayout() av.ChannelLayout {
	return self.ChannelLayout_
}

func (self CodecData) SampleRate() int {
	return self.SampleRate_
}



================================================
FILE: codec/h264parser/parser.go
================================================

package h264parser

import (
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/utils/bits"
	"github.com/nareix/joy4/utils/bits/pio"
	"fmt"
	"bytes"
)

const (
	NALU_SEI = 6
	NALU_PPS = 7
	NALU_SPS = 8
	NALU_AUD = 9
)

func IsDataNALU(b []byte) bool {
	typ := b[0] & 0x1f
	return typ >= 1 && typ <= 5
}

/*
From: http://stackoverflow.com/questions/24884827/possible-locations-for-sequence-picture-parameter-sets-for-h-264-stream

First off, it's important to understand that there is no single standard H.264 elementary bitstream format. The specification document does contain an Annex, specifically Annex B, that describes one possible format, but it is not an actual requirement. The standard specifies how video is encoded into individual packets. How these packets are stored and transmitted is left open to the integrator.

1. Annex B
Network Abstraction Layer Units
The packets are called Network Abstraction Layer Units. Often abbreviated NALU (or sometimes just NAL) each packet can be individually parsed and processed. The first byte of each NALU contains the NALU type, specifically bits 3 through 7. (bit 0 is always off, and bits 1-2 indicate whether a NALU is referenced by another NALU).

There are 19 different NALU types defined separated into two categories, VCL and non-VCL:

VCL, or Video Coding Layer packets contain the actual visual information.
Non-VCLs contain metadata that may or may not be required to decode the video.
A single NALU, or even a VCL NALU is NOT the same thing as a frame. A frame can be ‘sliced’ into several NALUs. Just like you can slice a pizza. One or more slices are then virtually grouped into a Access Units (AU) that contain one frame. Slicing does come at a slight quality cost, so it is not often used.

Below is a table of all defined NALUs.

0      Unspecified                                                    non-VCL
1      Coded slice of a non-IDR picture                               VCL
2      Coded slice data partition A                                   VCL
3      Coded slice data partition B                                   VCL
4      Coded slice data partition C                                   VCL
5      Coded slice of an IDR picture                                  VCL
6      Supplemental enhancement information (SEI)                     non-VCL
7      Sequence parameter set                                         non-VCL
8      Picture parameter set                                          non-VCL
9      Access unit delimiter                                          non-VCL
10     End of sequence                                                non-VCL
11     End of stream                                                  non-VCL
12     Filler data                                                    non-VCL
13     Sequence parameter set extension                               non-VCL
14     Prefix NAL unit                                                non-VCL
15     Subset sequence parameter set                                  non-VCL
16     Depth parameter set                                            non-VCL
17..18 Reserved                                                       non-VCL
19     Coded slice of an auxiliary coded picture without partitioning non-VCL
20     Coded slice extension                                          non-VCL
21     Coded slice extension for depth view components                non-VCL
22..23 Reserved                                                       non-VCL
24..31 Unspecified                                                    non-VCL
There are a couple of NALU types where having knowledge of may be helpful later.

Sequence Parameter Set (SPS). This non-VCL NALU contains information required to configure the decoder such as profile, level, resolution, frame rate.
Picture Parameter Set (PPS). Similar to the SPS, this non-VCL contains information on entropy coding mode, slice groups, motion prediction and deblocking filters.
Instantaneous Decoder Refresh (IDR). This VCL NALU is a self contained image slice. That is, an IDR can be decoded and displayed without referencing any other NALU save SPS and PPS.
Access Unit Delimiter (AUD). An AUD is an optional NALU that can be use to delimit frames in an elementary stream. It is not required (unless otherwise stated by the container/protocol, like TS), and is often not included in order to save space, but it can be useful to finds the start of a frame without having to fully parse each NALU.
NALU Start Codes
A NALU does not contain is its size. Therefore simply concatenating the NALUs to create a stream will not work because you will not know where one stops and the next begins.

The Annex B specification solves this by requiring ‘Start Codes’ to precede each NALU. A start code is 2 or 3 0x00 bytes followed with a 0x01 byte. e.g. 0x000001 or 0x00000001.

The 4 byte variation is useful for transmission over a serial connection as it is trivial to byte align the stream by looking for 31 zero bits followed by a one. If the next bit is 0 (because every NALU starts with a 0 bit), it is the start of a NALU. The 4 byte variation is usually only used for signaling random access points in the stream such as a SPS PPS AUD and IDR Where as the 3 byte variation is used everywhere else to save space.

Emulation Prevention Bytes
Start codes work because the four byte sequences 0x000000, 0x000001, 0x000002 and 0x000003 are illegal within a non-RBSP NALU. So when creating a NALU, care is taken to escape these values that could otherwise be confused with a start code. This is accomplished by inserting an ‘Emulation Prevention’ byte 0x03, so that 0x000001 becomes 0x00000301.

When decoding, it is important to look for and ignore emulation prevention bytes. Because emulation prevention bytes can occur almost anywhere within a NALU, it is often more convenient in documentation to assume they have already been removed. A representation without emulation prevention bytes is called Raw Byte Sequence Payload (RBSP).

Example
Let's look at a complete example.

0x0000 | 00 00 00 01 67 64 00 0A AC 72 84 44 26 84 00 00
0x0010 | 03 00 04 00 00 03 00 CA 3C 48 96 11 80 00 00 00
0x0020 | 01 68 E8 43 8F 13 21 30 00 00 01 65 88 81 00 05
0x0030 | 4E 7F 87 DF 61 A5 8B 95 EE A4 E9 38 B7 6A 30 6A
0x0040 | 71 B9 55 60 0B 76 2E B5 0E E4 80 59 27 B8 67 A9
0x0050 | 63 37 5E 82 20 55 FB E4 6A E9 37 35 72 E2 22 91
0x0060 | 9E 4D FF 60 86 CE 7E 42 B7 95 CE 2A E1 26 BE 87
0x0070 | 73 84 26 BA 16 36 F4 E6 9F 17 DA D8 64 75 54 B1
0x0080 | F3 45 0C 0B 3C 74 B3 9D BC EB 53 73 87 C3 0E 62
0x0090 | 47 48 62 CA 59 EB 86 3F 3A FA 86 B5 BF A8 6D 06
0x00A0 | 16 50 82 C4 CE 62 9E 4E E6 4C C7 30 3E DE A1 0B
0x00B0 | D8 83 0B B6 B8 28 BC A9 EB 77 43 FC 7A 17 94 85
0x00C0 | 21 CA 37 6B 30 95 B5 46 77 30 60 B7 12 D6 8C C5
0x00D0 | 54 85 29 D8 69 A9 6F 12 4E 71 DF E3 E2 B1 6B 6B
0x00E0 | BF 9F FB 2E 57 30 A9 69 76 C4 46 A2 DF FA 91 D9
0x00F0 | 50 74 55 1D 49 04 5A 1C D6 86 68 7C B6 61 48 6C
0x0100 | 96 E6 12 4C 27 AD BA C7 51 99 8E D0 F0 ED 8E F6
0x0110 | 65 79 79 A6 12 A1 95 DB C8 AE E3 B6 35 E6 8D BC
0x0120 | 48 A3 7F AF 4A 28 8A 53 E2 7E 68 08 9F 67 77 98
0x0130 | 52 DB 50 84 D6 5E 25 E1 4A 99 58 34 C7 11 D6 43
0x0140 | FF C4 FD 9A 44 16 D1 B2 FB 02 DB A1 89 69 34 C2
0x0150 | 32 55 98 F9 9B B2 31 3F 49 59 0C 06 8C DB A5 B2
0x0160 | 9D 7E 12 2F D0 87 94 44 E4 0A 76 EF 99 2D 91 18
0x0170 | 39 50 3B 29 3B F5 2C 97 73 48 91 83 B0 A6 F3 4B
0x0180 | 70 2F 1C 8F 3B 78 23 C6 AA 86 46 43 1D D7 2A 23
0x0190 | 5E 2C D9 48 0A F5 F5 2C D1 FB 3F F0 4B 78 37 E9
0x01A0 | 45 DD 72 CF 80 35 C3 95 07 F3 D9 06 E5 4A 58 76
0x01B0 | 03 6C 81 20 62 45 65 44 73 BC FE C1 9F 31 E5 DB
0x01C0 | 89 5C 6B 79 D8 68 90 D7 26 A8 A1 88 86 81 DC 9A
0x01D0 | 4F 40 A5 23 C7 DE BE 6F 76 AB 79 16 51 21 67 83
0x01E0 | 2E F3 D6 27 1A 42 C2 94 D1 5D 6C DB 4A 7A E2 CB
0x01F0 | 0B B0 68 0B BE 19 59 00 50 FC C0 BD 9D F5 F5 F8
0x0200 | A8 17 19 D6 B3 E9 74 BA 50 E5 2C 45 7B F9 93 EA
0x0210 | 5A F9 A9 30 B1 6F 5B 36 24 1E 8D 55 57 F4 CC 67
0x0220 | B2 65 6A A9 36 26 D0 06 B8 E2 E3 73 8B D1 C0 1C
0x0230 | 52 15 CA B5 AC 60 3E 36 42 F1 2C BD 99 77 AB A8
0x0240 | A9 A4 8E 9C 8B 84 DE 73 F0 91 29 97 AE DB AF D6
0x0250 | F8 5E 9B 86 B3 B3 03 B3 AC 75 6F A6 11 69 2F 3D
0x0260 | 3A CE FA 53 86 60 95 6C BB C5 4E F3

This is a complete AU containing 3 NALUs. As you can see, we begin with a Start code followed by an SPS (SPS starts with 67). Within the SPS, you will see two Emulation Prevention bytes. Without these bytes the illegal sequence 0x000000 would occur at these positions. Next you will see a start code followed by a PPS (PPS starts with 68) and one final start code followed by an IDR slice. This is a complete H.264 stream. If you type these values into a hex editor and save the file with a .264 extension, you will be able to convert it to this image:

Lena

Annex B is commonly used in live and streaming formats such as transport streams, over the air broadcasts, and DVDs. In these formats it is common to repeat the SPS and PPS periodically, usually preceding every IDR thus creating a random access point for the decoder. This enables the ability to join a stream already in progress.

2. AVCC
The other common method of storing an H.264 stream is the AVCC format. In this format, each NALU is preceded with its length (in big endian format). This method is easier to parse, but you lose the byte alignment features of Annex B. Just to complicate things, the length may be encoded using 1, 2 or 4 bytes. This value is stored in a header object. This header is often called ‘extradata’ or ‘sequence header’. Its basic format is as follows:

bits    
8   version ( always 0x01 )
8   avc profile ( sps[0][1] )
8   avc compatibility ( sps[0][2] )
8   avc level ( sps[0][3] )
6   reserved ( all bits on )
2   NALULengthSizeMinusOne
3   reserved ( all bits on )
5   number of SPS NALUs (usually 1)
repeated once per SPS:
  16         SPS size
	variable   SPS NALU data
8   number of PPS NALUs (usually 1)
repeated once per PPS
  16         PPS size
  variable   PPS NALU data

Using the same example above, the AVCC extradata will look like this:

0x0000 | 01 64 00 0A FF E1 00 19 67 64 00 0A AC 72 84 44
0x0010 | 26 84 00 00 03 00 04 00 00 03 00 CA 3C 48 96 11
0x0020 | 80 01 00 07 68 E8 43 8F 13 21 30

You will notice SPS and PPS is now stored out of band. That is, separate from the elementary stream data. Storage and transmission of this data is the job of the file container, and beyond the scope of this document. Notice that even though we are not using start codes, emulation prevention bytes are still inserted.

Additionally, there is a new variable called NALULengthSizeMinusOne. This confusingly named variable tells us how many bytes to use to store the length of each NALU. So, if NALULengthSizeMinusOne is set to 0, then each NALU is preceded with a single byte indicating its length. Using a single byte to store the size, the max size of a NALU is 255 bytes. That is obviously pretty small. Way too small for an entire key frame. Using 2 bytes gives us 64k per NALU. It would work in our example, but is still a pretty low limit. 3 bytes would be perfect, but for some reason is not universally supported. Therefore, 4 bytes is by far the most common, and it is what we used here:

0x0000 | 00 00 02 41 65 88 81 00 05 4E 7F 87 DF 61 A5 8B
0x0010 | 95 EE A4 E9 38 B7 6A 30 6A 71 B9 55 60 0B 76 2E
0x0020 | B5 0E E4 80 59 27 B8 67 A9 63 37 5E 82 20 55 FB
0x0030 | E4 6A E9 37 35 72 E2 22 91 9E 4D FF 60 86 CE 7E
0x0040 | 42 B7 95 CE 2A E1 26 BE 87 73 84 26 BA 16 36 F4
0x0050 | E6 9F 17 DA D8 64 75 54 B1 F3 45 0C 0B 3C 74 B3
0x0060 | 9D BC EB 53 73 87 C3 0E 62 47 48 62 CA 59 EB 86
0x0070 | 3F 3A FA 86 B5 BF A8 6D 06 16 50 82 C4 CE 62 9E
0x0080 | 4E E6 4C C7 30 3E DE A1 0B D8 83 0B B6 B8 28 BC
0x0090 | A9 EB 77 43 FC 7A 17 94 85 21 CA 37 6B 30 95 B5
0x00A0 | 46 77 30 60 B7 12 D6 8C C5 54 85 29 D8 69 A9 6F
0x00B0 | 12 4E 71 DF E3 E2 B1 6B 6B BF 9F FB 2E 57 30 A9
0x00C0 | 69 76 C4 46 A2 DF FA 91 D9 50 74 55 1D 49 04 5A
0x00D0 | 1C D6 86 68 7C B6 61 48 6C 96 E6 12 4C 27 AD BA
0x00E0 | C7 51 99 8E D0 F0 ED 8E F6 65 79 79 A6 12 A1 95
0x00F0 | DB C8 AE E3 B6 35 E6 8D BC 48 A3 7F AF 4A 28 8A
0x0100 | 53 E2 7E 68 08 9F 67 77 98 52 DB 50 84 D6 5E 25
0x0110 | E1 4A 99 58 34 C7 11 D6 43 FF C4 FD 9A 44 16 D1
0x0120 | B2 FB 02 DB A1 89 69 34 C2 32 55 98 F9 9B B2 31
0x0130 | 3F 49 59 0C 06 8C DB A5 B2 9D 7E 12 2F D0 87 94
0x0140 | 44 E4 0A 76 EF 99 2D 91 18 39 50 3B 29 3B F5 2C
0x0150 | 97 73 48 91 83 B0 A6 F3 4B 70 2F 1C 8F 3B 78 23
0x0160 | C6 AA 86 46 43 1D D7 2A 23 5E 2C D9 48 0A F5 F5
0x0170 | 2C D1 FB 3F F0 4B 78 37 E9 45 DD 72 CF 80 35 C3
0x0180 | 95 07 F3 D9 06 E5 4A 58 76 03 6C 81 20 62 45 65
0x0190 | 44 73 BC FE C1 9F 31 E5 DB 89 5C 6B 79 D8 68 90
0x01A0 | D7 26 A8 A1 88 86 81 DC 9A 4F 40 A5 23 C7 DE BE
0x01B0 | 6F 76 AB 79 16 51 21 67 83 2E F3 D6 27 1A 42 C2
0x01C0 | 94 D1 5D 6C DB 4A 7A E2 CB 0B B0 68 0B BE 19 59
0x01D0 | 00 50 FC C0 BD 9D F5 F5 F8 A8 17 19 D6 B3 E9 74
0x01E0 | BA 50 E5 2C 45 7B F9 93 EA 5A F9 A9 30 B1 6F 5B
0x01F0 | 36 24 1E 8D 55 57 F4 CC 67 B2 65 6A A9 36 26 D0
0x0200 | 06 B8 E2 E3 73 8B D1 C0 1C 52 15 CA B5 AC 60 3E
0x0210 | 36 42 F1 2C BD 99 77 AB A8 A9 A4 8E 9C 8B 84 DE
0x0220 | 73 F0 91 29 97 AE DB AF D6 F8 5E 9B 86 B3 B3 03
0x0230 | B3 AC 75 6F A6 11 69 2F 3D 3A CE FA 53 86 60 95
0x0240 | 6C BB C5 4E F3

An advantage to this format is the ability to configure the decoder at the start and jump into the middle of a stream. This is a common use case where the media is available on a random access medium such as a hard drive, and is therefore used in common container formats such as MP4 and MKV.
*/

var StartCodeBytes = []byte{0,0,1}
var AUDBytes = []byte{0,0,0,1,0x9,0xf0,0,0,0,1} // AUD

func CheckNALUsType(b []byte) (typ int) {
	_, typ = SplitNALUs(b)
	return
}

const (
	NALU_RAW = iota
	NALU_AVCC
	NALU_ANNEXB
)

func SplitNALUs(b []byte) (nalus [][]byte, typ int) {
	if len(b) < 4 {
		return [][]byte{b}, NALU_RAW
	}

	val3 := pio.U24BE(b)
	val4 := pio.U32BE(b)

	// maybe AVCC
	if val4 <= uint32(len(b)) {
		_val4 := val4
		_b := b[4:]
		nalus := [][]byte{}
		for {
			nalus = append(nalus, _b[:_val4])
			_b = _b[_val4:]
			if len(_b) < 4 {
				break
			}
			_val4 = pio.U32BE(_b)
			_b = _b[4:]
			if _val4 > uint32(len(_b)) {
				break
			}
		}
		if len(_b) == 0 {
			return nalus, NALU_AVCC
		}
	}

	// is Annex B
	if val3 == 1 || val4 == 1 {
		_val3 := val3
		_val4 := val4
		start := 0
		pos := 0
		for {
			if start != pos {
				nalus = append(nalus, b[start:pos])
			}
			if _val3 == 1 {
				pos += 3
			} else if _val4 == 1 {
				pos += 4
			}
			start = pos
			if start == len(b) {
				break
			}
			_val3 = 0
			_val4 = 0
			for pos < len(b) {
				if pos+2 < len(b) && b[pos] == 0 {
					_val3 = pio.U24BE(b[pos:])
					if _val3 == 0 {
						if pos+3 < len(b) {
							_val4 = uint32(b[pos+3])
							if _val4 == 1 {
								break
							}
						}
					} else if _val3 == 1 {
						break
					}
					pos++
				} else {
					pos++
				}
			}
		}
		typ = NALU_ANNEXB
		return
	}

	return [][]byte{b}, NALU_RAW
}

type SPSInfo struct {
	ProfileIdc uint
	LevelIdc   uint

	MbWidth  uint
	MbHeight uint

	CropLeft   uint
	CropRight  uint
	CropTop    uint
	CropBottom uint

	Width  uint
	Height uint
}

func ParseSPS(data []byte) (self SPSInfo, err error) {
	r := &bits.GolombBitReader{R: bytes.NewReader(data)}

	if _, err = r.ReadBits(8); err != nil {
		return
	}

	if self.ProfileIdc, err = r.ReadBits(8); err != nil {
		return
	}

	// constraint_set0_flag-constraint_set6_flag,reserved_zero_2bits
	if _, err = r.ReadBits(8); err != nil {
		return
	}

	// level_idc
	if self.LevelIdc, err = r.ReadBits(8); err != nil {
		return
	}

	// seq_parameter_set_id
	if _, err = r.ReadExponentialGolombCode(); err != nil {
		return
	}

	if self.ProfileIdc == 100 || self.ProfileIdc == 110 ||
		self.ProfileIdc == 122 || self.ProfileIdc == 244 ||
		self.ProfileIdc == 44 || self.ProfileIdc == 83 ||
		self.ProfileIdc == 86 || self.ProfileIdc == 118 {

		var chroma_format_idc uint
		if chroma_format_idc, err = r.ReadExponentialGolombCode(); err != nil {
			return
		}

		if chroma_format_idc == 3 {
			// residual_colour_transform_flag
			if _, err = r.ReadBit(); err != nil {
				return
			}
		}

		// bit_depth_luma_minus8
		if _, err = r.ReadExponentialGolombCode(); err != nil {
			return
		}
		// bit_depth_chroma_minus8
		if _, err = r.ReadExponentialGolombCode(); err != nil {
			return
		}
		// qpprime_y_zero_transform_bypass_flag
		if _, err = r.ReadBit(); err != nil {
			return
		}

		var seq_scaling_matrix_present_flag uint
		if seq_scaling_matrix_present_flag, err = r.ReadBit(); err != nil {
			return
		}

		if seq_scaling_matrix_present_flag != 0 {
			for i := 0; i < 8; i++ {
				var seq_scaling_list_present_flag uint
				if seq_scaling_list_present_flag, err = r.ReadBit(); err != nil {
					return
				}
				if seq_scaling_list_present_flag != 0 {
					var sizeOfScalingList uint
					if i < 6 {
						sizeOfScalingList = 16
					} else {
						sizeOfScalingList = 64
					}
					lastScale := uint(8)
					nextScale := uint(8)
					for j := uint(0); j < sizeOfScalingList; j++ {
						if nextScale != 0 {
							var delta_scale uint
							if delta_scale, err = r.ReadSE(); err != nil {
								return
							}
							nextScale = (lastScale + delta_scale + 256) % 256
						}
						if nextScale != 0 {
							lastScale = nextScale
						}
					}
				}
			}
		}
	}

	// log2_max_frame_num_minus4
	if _, err = r.ReadExponentialGolombCode(); err != nil {
		return
	}

	var pic_order_cnt_type uint
	if pic_order_cnt_type, err = r.ReadExponentialGolombCode(); err != nil {
		return
	}
	if pic_order_cnt_type == 0 {
		// log2_max_pic_order_cnt_lsb_minus4
		if _, err = r.ReadExponentialGolombCode(); err != nil {
			return
		}
	} else if pic_order_cnt_type == 1 {
		// delta_pic_order_always_zero_flag
		if _, err = r.ReadBit(); err != nil {
			return
		}
		// offset_for_non_ref_pic
		if _, err = r.ReadSE(); err != nil {
			return
		}
		// offset_for_top_to_bottom_field
		if _, err = r.ReadSE(); err != nil {
			return
		}
		var num_ref_frames_in_pic_order_cnt_cycle uint
		if num_ref_frames_in_pic_order_cnt_cycle, err = r.ReadExponentialGolombCode(); err != nil {
			return
		}
		for i := uint(0); i < num_ref_frames_in_pic_order_cnt_cycle; i++ {
			if _, err = r.ReadSE(); err != nil {
				return
			}
		}
	}

	// max_num_ref_frames
	if _, err = r.ReadExponentialGolombCode(); err != nil {
		return
	}

	// gaps_in_frame_num_value_allowed_flag
	if _, err = r.ReadBit(); err != nil {
		return
	}

	if self.MbWidth, err = r.ReadExponentialGolombCode(); err != nil {
		return
	}
	self.MbWidth++

	if self.MbHeight, err = r.ReadExponentialGolombCode(); err != nil {
		return
	}
	self.MbHeight++

	var frame_mbs_only_flag uint
	if frame_mbs_only_flag, err = r.ReadBit(); err != nil {
		return
	}
	if frame_mbs_only_flag == 0 {
		// mb_adaptive_frame_field_flag
		if _, err = r.ReadBit(); err != nil {
			return
		}
	}

	// direct_8x8_inference_flag
	if _, err = r.ReadBit(); err != nil {
		return
	}

	var frame_cropping_flag uint
	if frame_cropping_flag, err = r.ReadBit(); err != nil {
		return
	}
	if frame_cropping_flag != 0 {
		if self.CropLeft, err = r.ReadExponentialGolombCode(); err != nil {
			return
		}
		if self.CropRight, err = r.ReadExponentialGolombCode(); err != nil {
			return
		}
		if self.CropTop, err = r.ReadExponentialGolombCode(); err != nil {
			return
		}
		if self.CropBottom, err = r.ReadExponentialGolombCode(); err != nil {
			return
		}
	}

	self.Width = (self.MbWidth * 16) - self.CropLeft*2 - self.CropRight*2
	self.Height = ((2 - frame_mbs_only_flag) * self.MbHeight * 16) - self.CropTop*2 - self.CropBottom*2

	return
}

type CodecData struct {
	Record []byte
	RecordInfo AVCDecoderConfRecord
	SPSInfo SPSInfo
}

func (self CodecData) Type() av.CodecType {
	return av.H264
}

func (self CodecData) AVCDecoderConfRecordBytes() []byte {
	return self.Record
}

func (self CodecData) SPS() []byte {
	return self.RecordInfo.SPS[0]
}

func (self CodecData) PPS() []byte {
	return self.RecordInfo.PPS[0]
}

func (self CodecData) Width() int {
	return int(self.SPSInfo.Width)
}

func (self CodecData) Height() int {
	return int(self.SPSInfo.Height)
}

func NewCodecDataFromAVCDecoderConfRecord(record []byte) (self CodecData, err error) {
	self.Record = record
	if _, err = (&self.RecordInfo).Unmarshal(record); err != nil {
		return
	}
	if len(self.RecordInfo.SPS) == 0 {
		err = fmt.Errorf("h264parser: no SPS found in AVCDecoderConfRecord")
		return
	}
	if len(self.RecordInfo.PPS) == 0 {
		err = fmt.Errorf("h264parser: no PPS found in AVCDecoderConfRecord")
		return
	}
	if self.SPSInfo, err = ParseSPS(self.RecordInfo.SPS[0]); err != nil {
		err = fmt.Errorf("h264parser: parse SPS failed(%s)", err)
		return
	}
	return
}

func NewCodecDataFromSPSAndPPS(sps, pps []byte) (self CodecData, err error) {
	recordinfo := AVCDecoderConfRecord{}
	recordinfo.AVCProfileIndication = sps[1]
	recordinfo.ProfileCompatibility = sps[2]
	recordinfo.AVCLevelIndication = sps[3]
	recordinfo.SPS = [][]byte{sps}
	recordinfo.PPS = [][]byte{pps}
	recordinfo.LengthSizeMinusOne = 3

	buf := make([]byte, recordinfo.Len())
	recordinfo.Marshal(buf)

	self.RecordInfo = recordinfo
	self.Record = buf

	if self.SPSInfo, err = ParseSPS(sps); err != nil {
		return
	}
	return
}

type AVCDecoderConfRecord struct {
	AVCProfileIndication uint8
	ProfileCompatibility uint8
	AVCLevelIndication   uint8
	LengthSizeMinusOne   uint8
	SPS                  [][]byte
	PPS                  [][]byte
}

var ErrDecconfInvalid = fmt.Errorf("h264parser: AVCDecoderConfRecord invalid")

func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) {
	if len(b) < 7 {
		err = ErrDecconfInvalid
		return
	}

	self.AVCProfileIndication = b[1]
	self.ProfileCompatibility = b[2]
	self.AVCLevelIndication = b[3]
	self.LengthSizeMinusOne = b[4]&0x03
	spscount := int(b[5]&0x1f)
	n += 6

	for i := 0; i < spscount; i++ {
		if len(b) < n+2 {
			err = ErrDecconfInvalid
			return
		}
		spslen := int(pio.U16BE(b[n:]))
		n += 2

		if len(b) < n+spslen {
			err = ErrDecconfInvalid
			return
		}
		self.SPS = append(self.SPS, b[n:n+spslen])
		n += spslen
	}

	if len(b) < n+1 {
		err = ErrDecconfInvalid
		return
	}
	ppscount := int(b[n])
	n++

	for i := 0; i < ppscount; i++ {
		if len(b) < n+2 {
			err = ErrDecconfInvalid
			return
		}
		ppslen := int(pio.U16BE(b[n:]))
		n += 2

		if len(b) < n+ppslen {
			err = ErrDecconfInvalid
			return
		}
		self.PPS = append(self.PPS, b[n:n+ppslen])
		n += ppslen
	}

	return
}

func (self AVCDecoderConfRecord) Len() (n int) {
	n = 7
	for _, sps := range self.SPS {
		n += 2+len(sps)
	}
	for _, pps := range self.PPS {
		n += 2+len(pps)
	}
	return
}

func (self AVCDecoderConfRecord) Marshal(b []byte) (n int) {
	b[0] = 1
	b[1] = self.AVCProfileIndication
	b[2] = self.ProfileCompatibility
	b[3] = self.AVCLevelIndication
	b[4] = self.LengthSizeMinusOne|0xfc
	b[5] = uint8(len(self.SPS))|0xe0
	n += 6

	for _, sps := range self.SPS {
		pio.PutU16BE(b[n:], uint16(len(sps)))
		n += 2
		copy(b[n:], sps)
		n += len(sps)
	}

	b[n] = uint8(len(self.PPS))
	n++

	for _, pps := range self.PPS {
		pio.PutU16BE(b[n:], uint16(len(pps)))
		n += 2
		copy(b[n:], pps)
		n += len(pps)
	}

	return
}

type SliceType uint

func (self SliceType) String() string {
	switch self {
	case SLICE_P:
		return "P"
	case SLICE_B:
		return "B"
	case SLICE_I:
		return "I"
	}
	return ""
}

const (
	SLICE_P = iota+1
	SLICE_B
	SLICE_I
)

func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err error) {

	if len(packet) <= 1 {
		err = fmt.Errorf("h264parser: packet too short to parse slice header")
		return
	}

	nal_unit_type := packet[0]&0x1f
	switch nal_unit_type {
	case 1,2,5,19:
		// slice_layer_without_partitioning_rbsp
		// slice_data_partition_a_layer_rbsp

	default:
		err = fmt.Errorf("h264parser: nal_unit_type=%d has no slice header", nal_unit_type)
		return
	}

	r := &bits.GolombBitReader{R: bytes.NewReader(packet[1:])}

	// first_mb_in_slice
	if _, err = r.ReadExponentialGolombCode(); err != nil {
		return
	}

	// slice_type
	var u uint
	if u, err = r.ReadExponentialGolombCode(); err != nil {
		return
	}

	switch u {
	case 0,3,5,8:
		sliceType = SLICE_P
	case 1,6:
		sliceType = SLICE_B
	case 2,4,7,9:
		sliceType = SLICE_I
	default:
		err = fmt.Errorf("h264parser: slice_type=%d invalid", u)
		return
	}

	return
}



================================================
FILE: codec/h264parser/parser_test.go
================================================

package h264parser

import (
	"testing"
	"encoding/hex"
)

func TestParser(t *testing.T) {
	var ok bool
	var nalus [][]byte

	annexbFrame, _ := hex.DecodeString("00000001223322330000000122332233223300000133000001000001")
	nalus, ok = SplitNALUs(annexbFrame)
	t.Log(ok, len(nalus))

	avccFrame, _ := hex.DecodeString(
		"00000008aabbccaabbccaabb00000001aa",
	)
	nalus, ok = SplitNALUs(avccFrame)
	t.Log(ok, len(nalus))
}



================================================
FILE: doc.go
================================================

// Package joy4 is a Golang audio/video library and streaming server.
// JOY4 is powerful library written in golang, well-designed interface makes a few lines 
// of code can do a lot of things such as reading, writing, transcoding among 
// variety media formats, or setting up high-performance live streaming server.
package joy4


================================================
FILE: examples/audio_decode/main.go
================================================

package main

import (
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/format"
	"github.com/nareix/joy4/av/avutil"
	"github.com/nareix/joy4/cgo/ffmpeg"
)

// need ffmpeg installed

func init() {
	format.RegisterAll()
}

func main() {
	file, _ := avutil.Open("projectindex.flv")
	streams, _ := file.Streams()
	var dec *ffmpeg.AudioDecoder

	for _, stream := range streams {
		if stream.Type() == av.AAC {
			dec, _ = ffmpeg.NewAudioDecoder(stream.(av.AudioCodecData))
		}
	}

	for i := 0; i < 10; i++ {
		pkt, _ := file.ReadPacket()
		if streams[pkt.Idx].Type() == av.AAC {
			ok, frame, _ := dec.Decode(pkt.Data)
			if ok {
				println("decode samples", frame.SampleCount)
			}
		}
	}

	file.Close()
}



================================================
FILE: examples/http_flv_and_rtmp_server/main.go
================================================
package main

import (
	"sync"
	"io"
	"net/http"
	"github.com/nareix/joy4/format"
	"github.com/nareix/joy4/av/avutil"
	"github.com/nareix/joy4/av/pubsub"
	"github.com/nareix/joy4/format/rtmp"
	"github.com/nareix/joy4/format/flv"
)

func init() {
	format.RegisterAll()
}

type writeFlusher struct {
	httpflusher http.Flusher
	io.Writer
}

func (self writeFlusher) Flush() error {
	self.httpflusher.Flush()
	return nil
}

func main() {
	server := &rtmp.Server{}

	l := &sync.RWMutex{}
	type Channel struct {
		que *pubsub.Queue
	}
	channels := map[string]*Channel{}

	server.HandlePlay = func(conn *rtmp.Conn) {
		l.RLock()
		ch := channels[conn.URL.Path]
		l.RUnlock()

		if ch != nil {
			cursor := ch.que.Latest()
			avutil.CopyFile(conn, cursor)
		}
	}

	server.HandlePublish = func(conn *rtmp.Conn) {
		streams, _ := conn.Streams()

		l.Lock()
		ch := channels[conn.URL.Path]
		if ch == nil {
			ch = &Channel{}
			ch.que = pubsub.NewQueue()
			ch.que.WriteHeader(streams)
			channels[conn.URL.Path] = ch
		} else {
			ch = nil
		}
		l.Unlock()
		if ch == nil {
			return
		}

		avutil.CopyPackets(ch.que, conn)

		l.Lock()
		delete(channels, conn.URL.Path)
		l.Unlock()
		ch.que.Close()
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		l.RLock()
		ch := channels[r.URL.Path]
		l.RUnlock()

		if ch != nil {
			w.Header().Set("Content-Type", "video/x-flv")
			w.Header().Set("Transfer-Encoding", "chunked")		
			w.Header().Set("Access-Control-Allow-Origin", "*")
			w.WriteHeader(200)
			flusher := w.(http.Flusher)
			flusher.Flush()

			muxer := flv.NewMuxerWriteFlusher(writeFlusher{httpflusher: flusher, Writer: w})
			cursor := ch.que.Latest()

			avutil.CopyFile(muxer, cursor)
		} else {
			http.NotFound(w, r)
		}
	})

	go http.ListenAndServe(":8089", nil)

	server.ListenAndServe()

	// ffmpeg -re -i movie.flv -c copy -f flv rtmp://localhost/movie
	// ffmpeg -f avfoundation -i "0:0" .... -f flv rtmp://localhost/screen
	// ffplay http://localhost:8089/movie
	// ffplay http://localhost:8089/screen
}


================================================
FILE: examples/open_probe_file/main.go
================================================
package main

import (
	"fmt"
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/av/avutil"
	"github.com/nareix/joy4/format"
)

func init() {
	format.RegisterAll()
}

func main() {
	file, _ := avutil.Open("projectindex.flv")

	streams, _ := file.Streams()
	for _, stream := range streams {
		if stream.Type().IsAudio() {
			astream := stream.(av.AudioCodecData)
			fmt.Println(astream.Type(), astream.SampleRate(), astream.SampleFormat(), astream.ChannelLayout())
		} else if stream.Type().IsVideo() {
			vstream := stream.(av.VideoCodecData)
			fmt.Println(vstream.Type(), vstream.Width(), vstream.Height())
		}
	}

	for i := 0; i < 10; i++ {
		var pkt av.Packet
		var err error
		if pkt, err = file.ReadPacket(); err != nil {
			break
		}
		fmt.Println("pkt", i, streams[pkt.Idx].Type(), "len", len(pkt.Data), "keyframe", pkt.IsKeyFrame)
	}

	file.Close()
}



================================================
FILE: examples/rtmp_publish/main.go
================================================
package main

import (
	"github.com/nareix/joy4/av/pktque"
	"github.com/nareix/joy4/format"
	"github.com/nareix/joy4/av/avutil"
	"github.com/nareix/joy4/format/rtmp"
)

func init() {
	format.RegisterAll()
}

// as same as: ffmpeg -re -i projectindex.flv -c copy -f flv rtmp://localhost:1936/app/publish

func main() {
	file, _ := avutil.Open("projectindex.flv")
	conn, _ := rtmp.Dial("rtmp://localhost:1936/app/publish")
	// conn, _ := avutil.Create("rtmp://localhost:1936/app/publish")

	demuxer := &pktque.FilterDemuxer{Demuxer: file, Filter: &pktque.Walltime{}}
	avutil.CopyFile(conn, demuxer)

	file.Close()
	conn.Close()
}



================================================
FILE: examples/rtmp_server_channels/main.go
================================================
package main

import (
	"fmt"
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/av/avutil"
	"github.com/nareix/joy4/av/pktque"
	"github.com/nareix/joy4/av/pubsub"
	"github.com/nareix/joy4/format"
	"github.com/nareix/joy4/format/rtmp"
	"sync"
	"time"
)

func init() {
	format.RegisterAll()
}

type FrameDropper struct {
	Interval     int
	n            int
	skipping     bool
	DelaySkip    time.Duration
	lasttime     time.Time
	lastpkttime  time.Duration
	delay        time.Duration
	SkipInterval int
}

func (self *FrameDropper) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
	if self.DelaySkip != 0 && pkt.Idx == int8(videoidx) {
		now := time.Now()
		if !self.lasttime.IsZero() {
			realdiff := now.Sub(self.lasttime)
			pktdiff := pkt.Time - self.lastpkttime
			self.delay += realdiff - pktdiff
		}
		self.lasttime = time.Now()
		self.lastpkttime = pkt.Time

		if !self.skipping {
			if self.delay > self.DelaySkip {
				self.skipping = true
				self.delay = 0
			}
		} else {
			if pkt.IsKeyFrame {
				self.skipping = false
			}
		}
		if self.skipping {
			drop = true
		}

		if self.SkipInterval != 0 && pkt.IsKeyFrame {
			if self.n == self.SkipInterval {
				self.n = 0
				self.skipping = true
			}
			self.n++
		}
	}

	if self.Interval != 0 {
		if self.n >= self.Interval && pkt.Idx == int8(videoidx) && !pkt.IsKeyFrame {
			drop = true
			self.n = 0
		}
		self.n++
	}

	return
}

func main() {
	server := &rtmp.Server{}

	l := &sync.RWMutex{}
	type Channel struct {
		que *pubsub.Queue
	}
	channels := map[string]*Channel{}

	server.HandlePlay = func(conn *rtmp.Conn) {
		l.RLock()
		ch := channels[conn.URL.Path]
		l.RUnlock()

		if ch != nil {
			cursor := ch.que.Latest()
			query := conn.URL.Query()

			if q := query.Get("delaygop"); q != "" {
				n := 0
				fmt.Sscanf(q, "%d", &n)
				cursor = ch.que.DelayedGopCount(n)
			} else if q := query.Get("delaytime"); q != "" {
				dur, _ := time.ParseDuration(q)
				cursor = ch.que.DelayedTime(dur)
			}

			filters := pktque.Filters{}

			if q := query.Get("waitkey"); q != "" {
				filters = append(filters, &pktque.WaitKeyFrame{})
			}

			filters = append(filters, &pktque.FixTime{StartFromZero: true, MakeIncrement: true})

			if q := query.Get("framedrop"); q != "" {
				n := 0
				fmt.Sscanf(q, "%d", &n)
				filters = append(filters, &FrameDropper{Interval: n})
			}

			if q := query.Get("delayskip"); q != "" {
				dur, _ := time.ParseDuration(q)
				skipper := &FrameDropper{DelaySkip: dur}
				if q := query.Get("skipinterval"); q != "" {
					n := 0
					fmt.Sscanf(q, "%d", &n)
					skipper.SkipInterval = n
				}
				filters = append(filters, skipper)
			}

			demuxer := &pktque.FilterDemuxer{
				Filter:  filters,
				Demuxer: cursor,
			}

			avutil.CopyFile(conn, demuxer)
		}
	}

	server.HandlePublish = func(conn *rtmp.Conn) {
		l.Lock()
		ch := channels[conn.URL.Path]
		if ch == nil {
			ch = &Channel{}
			ch.que = pubsub.NewQueue()
			query := conn.URL.Query()
			if q := query.Get("cachegop"); q != "" {
				var n int
				fmt.Sscanf(q, "%d", &n)
				ch.que.SetMaxGopCount(n)
			}
			channels[conn.URL.Path] = ch
		} else {
			ch = nil
		}
		l.Unlock()
		if ch == nil {
			return
		}

		avutil.CopyFile(ch.que, conn)

		l.Lock()
		delete(channels, conn.URL.Path)
		l.Unlock()
		ch.que.Close()
	}

	server.ListenAndServe()

	// ffmpeg -re -i movie.flv -c copy -f flv rtmp://localhost/movie
	// ffmpeg -f avfoundation -i "0:0" .... -f flv rtmp://localhost/screen

	// with cache size options

	// ffplay rtmp://localhost/movie
	// ffplay rtmp://localhost/screen
	// ffplay rtmp://localhost/movie?delaytime=5s
	// ffplay rtmp://localhost/movie?delaytime=10s&waitkey=true
	// ffplay rtmp://localhost/movie?delaytime=20s

	// ffmpeg -re -i movie.flv -c copy -f flv rtmp://localhost/movie?cachegop=2
	// ffmpeg -re -i movie.flv -c copy -f flv rtmp://localhost/movie?cachegop=1
}


================================================
FILE: examples/rtmp_server_proxy/main.go
================================================
package main

import (
	"fmt"
	"strings"
	"github.com/nareix/joy4/format"
	"github.com/nareix/joy4/av/avutil"
	"github.com/nareix/joy4/format/rtmp"
)

func init() {
	format.RegisterAll()
}

func main() {
	server := &rtmp.Server{}

	server.HandlePlay = func(conn *rtmp.Conn) {
		segs := strings.Split(conn.URL.Path, "/")
		url := fmt.Sprintf("%s://%s", segs[1], strings.Join(segs[2:], "/"))
		src, _ := avutil.Open(url)
		avutil.CopyFile(conn, src)
	}

	server.ListenAndServe()

	// ffplay rtmp://localhost/rtsp/192.168.1.1/camera1
	// ffplay rtmp://localhost/rtmp/live.hkstv.hk.lxdns.com/live/hks
}


================================================
FILE: examples/rtmp_server_speex_to_aac/main.go
================================================
package main

import (
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/av/transcode"
	"github.com/nareix/joy4/format"
	"github.com/nareix/joy4/av/avutil"
	"github.com/nareix/joy4/format/rtmp"
	"github.com/nareix/joy4/cgo/ffmpeg"
)

// need ffmpeg with libspeex and libfdkaac installed
// 
// open http://www.wowza.com/resources/4.4.1/examples/WebcamRecording/FlashRTMPPlayer11/player.html
// click connect and recored
// input camera H264/SPEEX will converted H264/AAC and saved in out.ts

func init() {
	format.RegisterAll()
}

func main() {
	server := &rtmp.Server{}

	server.HandlePublish = func(conn *rtmp.Conn) {
		file, _ := avutil.Create("out.ts")

		findcodec := func(stream av.AudioCodecData, i int) (need bool, dec av.AudioDecoder, enc av.AudioEncoder, err error) {
			need = true
			dec, _ = ffmpeg.NewAudioDecoder(stream)
			enc, _ = ffmpeg.NewAudioEncoderByName("libfdk_aac")
			enc.SetSampleRate(48000)
			enc.SetChannelLayout(av.CH_STEREO)
			return
		}

		trans := &transcode.Demuxer{
			Options: transcode.Options{
				FindAudioDecoderEncoder: findcodec,
			},
			Demuxer: conn,
		}

		avutil.CopyFile(file, trans)
	}

	server.ListenAndServe()
}


================================================
FILE: examples/transcode/main.go
================================================
package main

import (
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/av/transcode"
	"github.com/nareix/joy4/format"
	"github.com/nareix/joy4/av/avutil"
	"github.com/nareix/joy4/cgo/ffmpeg"
)

// need ffmpeg with libfdkaac installed

func init() {
	format.RegisterAll()
}

func main() {
	infile, _ := avutil.Open("speex.flv")

	findcodec := func(stream av.AudioCodecData, i int) (need bool, dec av.AudioDecoder, enc av.AudioEncoder, err error) {
		need = true
		dec, _ = ffmpeg.NewAudioDecoder(stream)
		enc, _ = ffmpeg.NewAudioEncoderByName("libfdk_aac")
		enc.SetSampleRate(stream.SampleRate())
		enc.SetChannelLayout(av.CH_STEREO)
		enc.SetBitrate(12000)
		enc.SetOption("profile", "HE-AACv2")
		return
	}

	trans := &transcode.Demuxer{
		Options: transcode.Options{
			FindAudioDecoderEncoder: findcodec,
		},
		Demuxer: infile,
	}

	outfile, _ := avutil.Create("out.ts")
	avutil.CopyFile(outfile, trans)

	outfile.Close()
	infile.Close()
	trans.Close()
}



================================================
FILE: format/aac/aac.go
================================================

package aac

import (
	"github.com/nareix/joy4/av/avutil"
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/codec/aacparser"
	"time"
	"fmt"
	"io"
	"bufio"
)

type Muxer struct {
	w io.Writer
	config aacparser.MPEG4AudioConfig
	adtshdr []byte
}

func NewMuxer(w io.Writer) *Muxer {
	return &Muxer{
		adtshdr: make([]byte, aacparser.ADTSHeaderLength),
		w: w,
	}
}

func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) {
	if len(streams) > 1 || streams[0].Type() != av.AAC {
		err = fmt.Errorf("aac: must be only one aac stream")
		return
	}
	self.config = streams[0].(aacparser.CodecData).Config
	if self.config.ObjectType > aacparser.AOT_AAC_LTP {
		err = fmt.Errorf("aac: AOT %d is not allowed in ADTS", self.config.ObjectType)
	}
	return
}

func (self *Muxer) WritePacket(pkt av.Packet) (err error) {
	aacparser.FillADTSHeader(self.adtshdr, self.config, 1024, len(pkt.Data))
	if _, err = self.w.Write(self.adtshdr); err != nil {
		return
	}
	if _, err = self.w.Write(pkt.Data); err != nil {
		return
	}
	return
}

func (self *Muxer) WriteTrailer() (err error) {
	return
}

type Demuxer struct {
	r *bufio.Reader
	config aacparser.MPEG4AudioConfig
	codecdata av.CodecData
	ts time.Duration
}

func NewDemuxer(r io.Reader) *Demuxer {
	return &Demuxer{
		r: bufio.NewReader(r),
	}
}

func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
	if self.codecdata == nil {
		var adtshdr []byte
		var config aacparser.MPEG4AudioConfig
		if adtshdr, err = self.r.Peek(9); err != nil {
			return
		}
		if config, _, _, _, err = aacparser.ParseADTSHeader(adtshdr); err != nil {
			return
		}
		if self.codecdata, err = aacparser.NewCodecDataFromMPEG4AudioConfig(config); err != nil {
			return
		}
	}
	streams = []av.CodecData{self.codecdata}
	return
}

func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
	var adtshdr []byte
	var config aacparser.MPEG4AudioConfig
	var hdrlen, framelen, samples int
	if adtshdr, err = self.r.Peek(9); err != nil {
		return
	}
	if config, hdrlen, framelen, samples, err = aacparser.ParseADTSHeader(adtshdr); err != nil {
		return
	}

	pkt.Data = make([]byte, framelen)
	if _, err = io.ReadFull(self.r, pkt.Data); err != nil {
		return
	}
	pkt.Data = pkt.Data[hdrlen:]

	pkt.Time = self.ts
	self.ts += time.Duration(samples) * time.Second / time.Duration(config.SampleRate)
	return
}

func Handler(h *avutil.RegisterHandler) {
	h.Ext = ".aac"

	h.ReaderDemuxer = func(r io.Reader) av.Demuxer {
		return NewDemuxer(r)
	}

	h.WriterMuxer = func(w io.Writer) av.Muxer {
		return NewMuxer(w)
	}

	h.Probe = func(b []byte) bool {
		_, _, _, _, err := aacparser.ParseADTSHeader(b)
		return err == nil
	}

	h.CodecTypes = []av.CodecType{av.AAC}
}


================================================
FILE: format/flv/flv.go
================================================
package flv

import (
	"bufio"
	"fmt"
	"github.com/nareix/joy4/utils/bits/pio"
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/av/avutil"
	"github.com/nareix/joy4/codec"
	"github.com/nareix/joy4/codec/aacparser"
	"github.com/nareix/joy4/codec/fake"
	"github.com/nareix/joy4/codec/h264parser"
	"github.com/nareix/joy4/format/flv/flvio"
	"io"
)

var MaxProbePacketCount = 20

func NewMetadataByStreams(streams []av.CodecData) (metadata flvio.AMFMap, err error) {
	metadata = flvio.AMFMap{}

	for _, _stream := range streams {
		typ := _stream.Type()
		switch {
		case typ.IsVideo():
			stream := _stream.(av.VideoCodecData)
			switch typ {
			case av.H264:
				metadata["videocodecid"] = flvio.VIDEO_H264

			default:
				err = fmt.Errorf("flv: metadata: unsupported video codecType=%v", stream.Type())
				return
			}

			metadata["width"] = stream.Width()
			metadata["height"] = stream.Height()
			metadata["displayWidth"] = stream.Width()
			metadata["displayHeight"] = stream.Height()

		case typ.IsAudio():
			stream := _stream.(av.AudioCodecData)
			switch typ {
			case av.AAC:
				metadata["audiocodecid"] = flvio.SOUND_AAC

			case av.SPEEX:
				metadata["audiocodecid"] = flvio.SOUND_SPEEX

			default:
				err = fmt.Errorf("flv: metadata: unsupported audio codecType=%v", stream.Type())
				return
			}

			metadata["audiosamplerate"] = stream.SampleRate()
		}
	}

	return
}

type Prober struct {
	HasAudio, HasVideo             bool
	GotAudio, GotVideo             bool
	VideoStreamIdx, AudioStreamIdx int
	PushedCount                    int
	Streams                        []av.CodecData
	CachedPkts                     []av.Packet
}

func (self *Prober) CacheTag(_tag flvio.Tag, timestamp int32) {
	pkt, _ := self.TagToPacket(_tag, timestamp)
	self.CachedPkts = append(self.CachedPkts, pkt)
}

func (self *Prober) PushTag(tag flvio.Tag, timestamp int32) (err error) {
	self.PushedCount++

	if self.PushedCount > MaxProbePacketCount {
		err = fmt.Errorf("flv: max probe packet count reached")
		return
	}

	switch tag.Type {
	case flvio.TAG_VIDEO:
		switch tag.AVCPacketType {
		case flvio.AVC_SEQHDR:
			if !self.GotVideo {
				var stream h264parser.CodecData
				if stream, err = h264parser.NewCodecDataFromAVCDecoderConfRecord(tag.Data); err != nil {
					err = fmt.Errorf("flv: h264 seqhdr invalid")
					return
				}
				self.VideoStreamIdx = len(self.Streams)
				self.Streams = append(self.Streams, stream)
				self.GotVideo = true
			}

		case flvio.AVC_NALU:
			self.CacheTag(tag, timestamp)
		}

	case flvio.TAG_AUDIO:
		switch tag.SoundFormat {
		case flvio.SOUND_AAC:
			switch tag.AACPacketType {
			case flvio.AAC_SEQHDR:
				if !self.GotAudio {
					var stream aacparser.CodecData
					if stream, err = aacparser.NewCodecDataFromMPEG4AudioConfigBytes(tag.Data); err != nil {
						err = fmt.Errorf("flv: aac seqhdr invalid")
						return
					}
					self.AudioStreamIdx = len(self.Streams)
					self.Streams = append(self.Streams, stream)
					self.GotAudio = true
				}

			case flvio.AAC_RAW:
				self.CacheTag(tag, timestamp)
			}

		case flvio.SOUND_SPEEX:
			if !self.GotAudio {
				stream := codec.NewSpeexCodecData(16000, tag.ChannelLayout())
				self.AudioStreamIdx = len(self.Streams)
				self.Streams = append(self.Streams, stream)
				self.GotAudio = true
				self.CacheTag(tag, timestamp)
			}

		case flvio.SOUND_NELLYMOSER:
			if !self.GotAudio {
				stream := fake.CodecData{
					CodecType_:     av.NELLYMOSER,
					SampleRate_:    16000,
					SampleFormat_:  av.S16,
					ChannelLayout_: tag.ChannelLayout(),
				}
				self.AudioStreamIdx = len(self.Streams)
				self.Streams = append(self.Streams, stream)
				self.GotAudio = true
				self.CacheTag(tag, timestamp)
			}

		}
	}

	return
}

func (self *Prober) Probed() (ok bool) {
	if self.HasAudio || self.HasVideo {
		if self.HasAudio == self.GotAudio && self.HasVideo == self.GotVideo {
			return true
		}
	} else {
		if self.PushedCount == MaxProbePacketCount {
			return true
		}
	}
	return
}

func (self *Prober) TagToPacket(tag flvio.Tag, timestamp int32) (pkt av.Packet, ok bool) {
	switch tag.Type {
	case flvio.TAG_VIDEO:
		pkt.Idx = int8(self.VideoStreamIdx)
		switch tag.AVCPacketType {
		case flvio.AVC_NALU:
			ok = true
			pkt.Data = tag.Data
			pkt.CompositionTime = flvio.TsToTime(tag.CompositionTime)
			pkt.IsKeyFrame = tag.FrameType == flvio.FRAME_KEY
		}

	case flvio.TAG_AUDIO:
		pkt.Idx = int8(self.AudioStreamIdx)
		switch tag.SoundFormat {
		case flvio.SOUND_AAC:
			switch tag.AACPacketType {
			case flvio.AAC_RAW:
				ok = true
				pkt.Data = tag.Data
			}

		case flvio.SOUND_SPEEX:
			ok = true
			pkt.Data = tag.Data

		case flvio.SOUND_NELLYMOSER:
			ok = true
			pkt.Data = tag.Data
		}
	}

	pkt.Time = flvio.TsToTime(timestamp)
	return
}

func (self *Prober) Empty() bool {
	return len(self.CachedPkts) == 0
}

func (self *Prober) PopPacket() av.Packet {
	pkt := self.CachedPkts[0]
	self.CachedPkts = self.CachedPkts[1:]
	return pkt
}

func CodecDataToTag(stream av.CodecData) (_tag flvio.Tag, ok bool, err error) {
	switch stream.Type() {
	case av.H264:
		h264 := stream.(h264parser.CodecData)
		tag := flvio.Tag{
			Type:          flvio.TAG_VIDEO,
			AVCPacketType: flvio.AVC_SEQHDR,
			CodecID:       flvio.VIDEO_H264,
			Data:          h264.AVCDecoderConfRecordBytes(),
			FrameType:     flvio.FRAME_KEY,
		}
		ok = true
		_tag = tag

	case av.NELLYMOSER:
	case av.SPEEX:

	case av.AAC:
		aac := stream.(aacparser.CodecData)
		tag := flvio.Tag{
			Type:          flvio.TAG_AUDIO,
			SoundFormat:   flvio.SOUND_AAC,
			SoundRate:     flvio.SOUND_44Khz,
			AACPacketType: flvio.AAC_SEQHDR,
			Data:          aac.MPEG4AudioConfigBytes(),
		}
		switch aac.SampleFormat().BytesPerSample() {
		case 1:
			tag.SoundSize = flvio.SOUND_8BIT
		default:
			tag.SoundSize = flvio.SOUND_16BIT
		}
		switch aac.ChannelLayout().Count() {
		case 1:
			tag.SoundType = flvio.SOUND_MONO
		case 2:
			tag.SoundType = flvio.SOUND_STEREO
		}
		ok = true
		_tag = tag

	default:
		err = fmt.Errorf("flv: unspported codecType=%v", stream.Type())
		return
	}
	return
}

func PacketToTag(pkt av.Packet, stream av.CodecData) (tag flvio.Tag, timestamp int32) {
	switch stream.Type() {
	case av.H264:
		tag = flvio.Tag{
			Type:            flvio.TAG_VIDEO,
			AVCPacketType:   flvio.AVC_NALU,
			CodecID:         flvio.VIDEO_H264,
			Data:            pkt.Data,
			CompositionTime: flvio.TimeToTs(pkt.CompositionTime),
		}
		if pkt.IsKeyFrame {
			tag.FrameType = flvio.FRAME_KEY
		} else {
			tag.FrameType = flvio.FRAME_INTER
		}

	case av.AAC:
		tag = flvio.Tag{
			Type:          flvio.TAG_AUDIO,
			SoundFormat:   flvio.SOUND_AAC,
			SoundRate:     flvio.SOUND_44Khz,
			AACPacketType: flvio.AAC_RAW,
			Data:          pkt.Data,
		}
		astream := stream.(av.AudioCodecData)
		switch astream.SampleFormat().BytesPerSample() {
		case 1:
			tag.SoundSize = flvio.SOUND_8BIT
		default:
			tag.SoundSize = flvio.SOUND_16BIT
		}
		switch astream.ChannelLayout().Count() {
		case 1:
			tag.SoundType = flvio.SOUND_MONO
		case 2:
			tag.SoundType = flvio.SOUND_STEREO
		}

	case av.SPEEX:
		tag = flvio.Tag{
			Type:        flvio.TAG_AUDIO,
			SoundFormat: flvio.SOUND_SPEEX,
			Data:        pkt.Data,
		}

	case av.NELLYMOSER:
		tag = flvio.Tag{
			Type:        flvio.TAG_AUDIO,
			SoundFormat: flvio.SOUND_NELLYMOSER,
			Data:        pkt.Data,
		}
	}

	timestamp = flvio.TimeToTs(pkt.Time)
	return
}

type Muxer struct {
	bufw    writeFlusher
	b       []byte
	streams []av.CodecData
}

type writeFlusher interface {
	io.Writer
	Flush() error
}

func NewMuxerWriteFlusher(w writeFlusher) *Muxer {
	return &Muxer{
		bufw: w,
		b:    make([]byte, 256),
	}
}

func NewMuxer(w io.Writer) *Muxer {
	return NewMuxerWriteFlusher(bufio.NewWriterSize(w, pio.RecommendBufioSize))
}

var CodecTypes = []av.CodecType{av.H264, av.AAC, av.SPEEX}

func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) {
	var flags uint8
	for _, stream := range streams {
		if stream.Type().IsVideo() {
			flags |= flvio.FILE_HAS_VIDEO
		} else if stream.Type().IsAudio() {
			flags |= flvio.FILE_HAS_AUDIO
		}
	}

	n := flvio.FillFileHeader(self.b, flags)
	if _, err = self.bufw.Write(self.b[:n]); err != nil {
		return
	}

	for _, stream := range streams {
		var tag flvio.Tag
		var ok bool
		if tag, ok, err = CodecDataToTag(stream); err != nil {
			return
		}
		if ok {
			if err = flvio.WriteTag(self.bufw, tag, 0, self.b); err != nil {
				return
			}
		}
	}

	self.streams = streams
	return
}

func (self *Muxer) WritePacket(pkt av.Packet) (err error) {
	stream := self.streams[pkt.Idx]
	tag, timestamp := PacketToTag(pkt, stream)

	if err = flvio.WriteTag(self.bufw, tag, timestamp, self.b); err != nil {
		return
	}
	return
}

func (self *Muxer) WriteTrailer() (err error) {
	if err = self.bufw.Flush(); err != nil {
		return
	}
	return
}

type Demuxer struct {
	prober *Prober
	bufr   *bufio.Reader
	b      []byte
	stage  int
}

func NewDemuxer(r io.Reader) *Demuxer {
	return &Demuxer{
		bufr:   bufio.NewReaderSize(r, pio.RecommendBufioSize),
		prober: &Prober{},
		b:      make([]byte, 256),
	}
}

func (self *Demuxer) prepare() (err error) {
	for self.stage < 2 {
		switch self.stage {
		case 0:
			if _, err = io.ReadFull(self.bufr, self.b[:flvio.FileHeaderLength]); err != nil {
				return
			}
			var flags uint8
			var skip int
			if flags, skip, err = flvio.ParseFileHeader(self.b); err != nil {
				return
			}
			if _, err = self.bufr.Discard(skip); err != nil {
				return
			}
			if flags&flvio.FILE_HAS_AUDIO != 0 {
				self.prober.HasAudio = true
			}
			if flags&flvio.FILE_HAS_VIDEO != 0 {
				self.prober.HasVideo = true
			}
			self.stage++

		case 1:
			for !self.prober.Probed() {
				var tag flvio.Tag
				var timestamp int32
				if tag, timestamp, err = flvio.ReadTag(self.bufr, self.b); err != nil {
					return
				}
				if err = self.prober.PushTag(tag, timestamp); err != nil {
					return
				}
			}
			self.stage++
		}
	}
	return
}

func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
	if err = self.prepare(); err != nil {
		return
	}
	streams = self.prober.Streams
	return
}

func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
	if err = self.prepare(); err != nil {
		return
	}

	if !self.prober.Empty() {
		pkt = self.prober.PopPacket()
		return
	}

	for {
		var tag flvio.Tag
		var timestamp int32
		if tag, timestamp, err = flvio.ReadTag(self.bufr, self.b); err != nil {
			return
		}

		var ok bool
		if pkt, ok = self.prober.TagToPacket(tag, timestamp); ok {
			return
		}
	}

	return
}

func Handler(h *avutil.RegisterHandler) {
	h.Probe = func(b []byte) bool {
		return b[0] == 'F' && b[1] == 'L' && b[2] == 'V'
	}

	h.Ext = ".flv"

	h.ReaderDemuxer = func(r io.Reader) av.Demuxer {
		return NewDemuxer(r)
	}

	h.WriterMuxer = func(w io.Writer) av.Muxer {
		return NewMuxer(w)
	}

	h.CodecTypes = CodecTypes
}


================================================
FILE: format/flv/flvio/amf0.go
================================================
package flvio

import (
	"strings"
	"math"
	"fmt"
	"time"
	"github.com/nareix/joy4/utils/bits/pio"
)

type AMF0ParseError struct {
	Offset int
	Message string
	Next *AMF0ParseError
}

func (self *AMF0ParseError) Error() string {
	s := []string{}
	for p := self; p != nil; p = p.Next {
		s = append(s, fmt.Sprintf("%s:%d", p.Message, p.Offset))
	}
	return "amf0 parse error: " + strings.Join(s, ",")
}

func amf0ParseErr(message string, offset int, err error) error {
	next, _ := err.(*AMF0ParseError)
	return &AMF0ParseError{
		Offset: offset,
		Message: message,
		Next: next,
	}
}

type AMFMap map[string]interface{}
type AMFArray []interface{}
type AMFECMAArray map[string]interface{}

func parseBEFloat64(b []byte) float64 {
	return math.Float64frombits(pio.U64BE(b))
}

func fillBEFloat64(b []byte, f float64) int {
	pio.PutU64BE(b, math.Float64bits(f))
	return 8
}

const lenAMF0Number = 9

func fillAMF0Number(b []byte, f float64) int {
	b[0] = numbermarker
	fillBEFloat64(b[1:], f)
	return lenAMF0Number
}

const (
	amf3undefinedmarker = iota
	amf3nullmarker
	amf3falsemarker
	amf3truemarker
	amf3integermarker
	amf3doublemarker
	amf3stringmarker
	amf3xmldocmarker
	amf3datemarker
	amf3arraymarker
	amf3objectmarker
	amf3xmlmarker
	amf3bytearraymarker
	amf3vectorintmarker
	amf3vectoruintmarker
	amf3vectordoublemarker
	amf3vectorobjectmarker
	amf3dictionarymarker
)

const (
	numbermarker = iota
	booleanmarker
	stringmarker
	objectmarker
	movieclipmarker
	nullmarker
	undefinedmarker
	referencemarker
	ecmaarraymarker
	objectendmarker
	strictarraymarker
	datemarker
	longstringmarker
	unsupportedmarker
	recordsetmarker
	xmldocumentmarker
	typedobjectmarker
	avmplusobjectmarker
)

func LenAMF0Val(_val interface{}) (n int) {
	switch val := _val.(type) {
	case int8:
		n += lenAMF0Number
	case int16:
		n += lenAMF0Number
	case int32:
		n += lenAMF0Number
	case int64:
		n += lenAMF0Number
	case int:
		n += lenAMF0Number
	case uint8:
		n += lenAMF0Number
	case uint16:
		n += lenAMF0Number
	case uint32:
		n += lenAMF0Number
	case uint64:
		n += lenAMF0Number
	case uint:
		n += lenAMF0Number
	case float32:
		n += lenAMF0Number
	case float64:
		n += lenAMF0Number

	case string:
		u := len(val)
		if u <= 65536 {
			n += 3
		} else {
			n += 5
		}
		n += int(u)

	case AMFECMAArray:
		n += 5
		for k, v := range val {
			n += 2+len(k)
			n += LenAMF0Val(v)
		}
		n += 3

	case AMFMap:
		n++
		for k, v := range val {
			if len(k) > 0 {
				n += 2+len(k)
				n += LenAMF0Val(v)
			}
		}
		n += 3

	case AMFArray:
		n += 5
		for _, v := range val {
			n += LenAMF0Val(v)
		}

	case time.Time:
		n += 1+8+2

	case bool:
		n += 2

	case nil:
		n++
	}

	return
}

func FillAMF0Val(b []byte, _val interface{}) (n int) {
	switch val := _val.(type) {
	case int8:
		n += fillAMF0Number(b[n:], float64(val))
	case int16:
		n += fillAMF0Number(b[n:], float64(val))
	case int32:
		n += fillAMF0Number(b[n:], float64(val))
	case int64:
		n += fillAMF0Number(b[n:], float64(val))
	case int:
		n += fillAMF0Number(b[n:], float64(val))
	case uint8:
		n += fillAMF0Number(b[n:], float64(val))
	case uint16:
		n += fillAMF0Number(b[n:], float64(val))
	case uint32:
		n += fillAMF0Number(b[n:], float64(val))
	case uint64:
		n += fillAMF0Number(b[n:], float64(val))
	case uint:
		n += fillAMF0Number(b[n:], float64(val))
	case float32:
		n += fillAMF0Number(b[n:], float64(val))
	case float64:
		n += fillAMF0Number(b[n:], float64(val))

	case string:
		u := len(val)
		if u <= 65536 {
			b[n] = stringmarker
			n++
			pio.PutU16BE(b[n:], uint16(u))
			n += 2
		} else {
			b[n] = longstringmarker
			n++
			pio.PutU32BE(b[n:], uint32(u))
			n += 4
		}
		copy(b[n:], []byte(val))
		n += len(val)

	case AMFECMAArray:
		b[n] = ecmaarraymarker
		n++
		pio.PutU32BE(b[n:], uint32(len(val)))
		n += 4
		for k, v := range val {
			pio.PutU16BE(b[n:], uint16(len(k)))
			n += 2
			copy(b[n:], []byte(k))
			n += len(k)
			n += FillAMF0Val(b[n:], v)
		}
		pio.PutU24BE(b[n:], 0x000009)
		n += 3

	case AMFMap:
		b[n] = objectmarker
		n++
		for k, v := range val {
			if len(k) > 0 {
				pio.PutU16BE(b[n:], uint16(len(k)))
				n += 2
				copy(b[n:], []byte(k))
				n += len(k)
				n += FillAMF0Val(b[n:], v)
			}
		}
		pio.PutU24BE(b[n:], 0x000009)
		n += 3

	case AMFArray:
		b[n] = strictarraymarker
		n++
		pio.PutU32BE(b[n:], uint32(len(val)))
		n += 4
		for _, v := range val {
			n += FillAMF0Val(b[n:], v)
		}

	case time.Time:
		b[n] = datemarker
		n++
		u := val.UnixNano()
		f := float64(u/1000000)
		n += fillBEFloat64(b[n:], f)
		pio.PutU16BE(b[n:], uint16(0))
		n += 2

	case bool:
		b[n] = booleanmarker
		n++
		var u uint8
		if val {
			u = 1
		} else {
			u = 0
		}
		b[n] = u
		n++

	case nil:
		b[n] = nullmarker
		n++
	}

	return
}


func ParseAMF0Val(b []byte) (val interface{}, n int, err error) {
	return parseAMF0Val(b, 0)
}

func parseAMF0Val(b []byte, offset int) (val interface{}, n int, err error) {
	if len(b) < n+1 {
		err = amf0ParseErr("marker", offset+n, err)
		return
	}
	marker := b[n]
	n++

	switch marker {
	case numbermarker:
		if len(b) < n+8 {
			err = amf0ParseErr("number", offset+n, err)
			return
		}
		val = parseBEFloat64(b[n:])
		n += 8

	case booleanmarker:
		if len(b) < n+1 {
			err = amf0ParseErr("boolean", offset+n, err)
			return
		}
		val = b[n] != 0
		n++

	case stringmarker:
		if len(b) < n+2 {
			err = amf0ParseErr("string.length", offset+n, err)
			return
		}
		length := int(pio.U16BE(b[n:]))
		n += 2

		if len(b) < n+length {
			err = amf0ParseErr("string.body", offset+n, err)
			return
		}
		val = string(b[n:n+length])
		n += length

	case objectmarker:
		obj := AMFMap{}
		for {
			if len(b) < n+2 {
				err = amf0ParseErr("object.key.length", offset+n, err)
				return
			}
			length := int(pio.U16BE(b[n:]))
			n += 2
			if length == 0 {
				break
			}

			if len(b) < n+length {
				err = amf0ParseErr("object.key.body", offset+n, err)
				return
			}
			okey := string(b[n:n+length])
			n += length

			var nval int
			var oval interface{}
			if oval, nval, err = parseAMF0Val(b[n:], offset+n); err != nil {
				err = amf0ParseErr("object.val", offset+n, err)
				return
			}
			n += nval

			obj[okey] = oval
		}
		if len(b) < n+1 {
			err = amf0ParseErr("object.end", offset+n, err)
			return
		}
		n++
		val = obj

	case nullmarker:
	case undefinedmarker:

	case ecmaarraymarker:
		if len(b) < n+4 {
			err = amf0ParseErr("array.count", offset+n, err)
			return
		}
		n += 4

		obj := AMFMap{}
		for {
			if len(b) < n+2 {
				err = amf0ParseErr("array.key.length", offset+n, err)
				return
			}
			length := int(pio.U16BE(b[n:]))
			n += 2

			if length == 0 {
				break
			}

			if len(b) < n+length {
				err = amf0ParseErr("array.key.body", offset+n, err)
				return
			}
			okey := string(b[n:n+length])
			n += length

			var nval int
			var oval interface{}
			if oval, nval, err = parseAMF0Val(b[n:], offset+n); err != nil {
				err = amf0ParseErr("array.val", offset+n, err)
				return
			}
			n += nval

			obj[okey] = oval
		}
		if len(b) < n+1 {
			err = amf0ParseErr("array.end", offset+n, err)
			return
		}
		n += 1
		val = obj

	case objectendmarker:
		if len(b) < n+3 {
			err = amf0ParseErr("objectend", offset+n, err)
			return
		}
		n += 3

	case strictarraymarker:
		if len(b) < n+4 {
			err = amf0ParseErr("strictarray.count", offset+n, err)
			return
		}
		count := int(pio.U32BE(b[n:]))
		n += 4

		obj := make(AMFArray, count)
		for i := 0; i < int(count); i++ {
			var nval int
			if obj[i], nval, err = parseAMF0Val(b[n:], offset+n); err != nil {
				err = amf0ParseErr("strictarray.val", offset+n, err)
				return
			}
			n += nval
		}
		val = obj

	case datemarker:
		if len(b) < n+8+2 {
			err = amf0ParseErr("date", offset+n, err)
			return
		}
		ts := parseBEFloat64(b[n:])
		n += 8+2

		val = time.Unix(int64(ts/1000), (int64(ts)%1000)*1000000)

	case longstringmarker:
		if len(b) < n+4 {
			err = amf0ParseErr("longstring.length", offset+n, err)
			return
		}
		length := int(pio.U32BE(b[n:]))
		n += 4

		if len(b) < n+length {
			err = amf0ParseErr("longstring.body", offset+n, err)
			return
		}
		val = string(b[n:n+length])
		n += length

	default:
		err = amf0ParseErr(fmt.Sprintf("invalidmarker=%d", marker), offset+n, err)
		return
	}

	return
}



================================================
FILE: format/flv/flvio/flvio.go
================================================
package flvio

import (
	"fmt"
	"github.com/nareix/joy4/utils/bits/pio"
	"github.com/nareix/joy4/av"
	"io"
	"time"
)

func TsToTime(ts int32) time.Duration {
	return time.Millisecond * time.Duration(ts)
}

func TimeToTs(tm time.Duration) int32 {
	return int32(tm / time.Millisecond)
}

const MaxTagSubHeaderLength = 16

const (
	TAG_AUDIO      = 8
	TAG_VIDEO      = 9
	TAG_SCRIPTDATA = 18
)

const (
	SOUND_MP3                   = 2
	SOUND_NELLYMOSER_16KHZ_MONO = 4
	SOUND_NELLYMOSER_8KHZ_MONO  = 5
	SOUND_NELLYMOSER            = 6
	SOUND_ALAW                  = 7
	SOUND_MULAW                 = 8
	SOUND_AAC                   = 10
	SOUND_SPEEX                 = 11

	SOUND_5_5Khz = 0
	SOUND_11Khz  = 1
	SOUND_22Khz  = 2
	SOUND_44Khz  = 3

	SOUND_8BIT  = 0
	SOUND_16BIT = 1

	SOUND_MONO   = 0
	SOUND_STEREO = 1

	AAC_SEQHDR = 0
	AAC_RAW    = 1
)

const (
	AVC_SEQHDR = 0
	AVC_NALU   = 1
	AVC_EOS    = 2

	FRAME_KEY   = 1
	FRAME_INTER = 2

	VIDEO_H264 = 7
)

type Tag struct {
	Type uint8

	/*
		SoundFormat: UB[4]
		0 = Linear PCM, platform endian
		1 = ADPCM
		2 = MP3
		3 = Linear PCM, little endian
		4 = Nellymoser 16-kHz mono
		5 = Nellymoser 8-kHz mono
		6 = Nellymoser
		7 = G.711 A-law logarithmic PCM
		8 = G.711 mu-law logarithmic PCM
		9 = reserved
		10 = AAC
		11 = Speex
		14 = MP3 8-Khz
		15 = Device-specific sound
		Formats 7, 8, 14, and 15 are reserved for internal use
		AAC is supported in Flash Player 9,0,115,0 and higher.
		Speex is supported in Flash Player 10 and higher.
	*/
	SoundFormat uint8

	/*
		SoundRate: UB[2]
		Sampling rate
		0 = 5.5-kHz For AAC: always 3
		1 = 11-kHz
		2 = 22-kHz
		3 = 44-kHz
	*/
	SoundRate uint8

	/*
		SoundSize: UB[1]
		0 = snd8Bit
		1 = snd16Bit
		Size of each sample.
		This parameter only pertains to uncompressed formats.
		Compressed formats always decode to 16 bits internally
	*/
	SoundSize uint8

	/*
		SoundType: UB[1]
		0 = sndMono
		1 = sndStereo
		Mono or stereo sound For Nellymoser: always 0
		For AAC: always 1
	*/
	SoundType uint8

	/*
		0: AAC sequence header
		1: AAC raw
	*/
	AACPacketType uint8

	/*
		1: keyframe (for AVC, a seekable frame)
		2: inter frame (for AVC, a non- seekable frame)
		3: disposable inter frame (H.263 only)
		4: generated keyframe (reserved for server use only)
		5: video info/command frame
	*/
	FrameType uint8

	/*
		1: JPEG (currently unused)
		2: Sorenson H.263
		3: Screen video
		4: On2 VP6
		5: On2 VP6 with alpha channel
		6: Screen video version 2
		7: AVC
	*/
	CodecID uint8

	/*
		0: AVC sequence header
		1: AVC NALU
		2: AVC end of sequence (lower level NALU sequence ender is not required or supported)
	*/
	AVCPacketType uint8

	CompositionTime int32

	Data []byte
}

func (self Tag) ChannelLayout() av.ChannelLayout {
	if self.SoundType == SOUND_MONO {
		return av.CH_MONO
	} else {
		return av.CH_STEREO
	}
}

func (self *Tag) audioParseHeader(b []byte) (n int, err error) {
	if len(b) < n+1 {
		err = fmt.Errorf("audiodata: parse invalid")
		return
	}

	flags := b[n]
	n++
	self.SoundFormat = flags >> 4
	self.SoundRate = (flags >> 2) & 0x3
	self.SoundSize = (flags >> 1) & 0x1
	self.SoundType = flags & 0x1

	switch self.SoundFormat {
	case SOUND_AAC:
		if len(b) < n+1 {
			err = fmt.Errorf("audiodata: parse invalid")
			return
		}
		self.AACPacketType = b[n]
		n++
	}

	return
}

func (self Tag) audioFillHeader(b []byte) (n int) {
	var flags uint8
	flags |= self.SoundFormat << 4
	flags |= self.SoundRate << 2
	flags |= self.SoundSize << 1
	flags |= self.SoundType
	b[n] = flags
	n++

	switch self.SoundFormat {
	case SOUND_AAC:
		b[n] = self.AACPacketType
		n++
	}

	return
}

func (self *Tag) videoParseHeader(b []byte) (n int, err error) {
	if len(b) < n+1 {
		err = fmt.Errorf("videodata: parse invalid")
		return
	}
	flags := b[n]
	self.FrameType = flags >> 4
	self.CodecID = flags & 0xf
	n++

	if self.FrameType == FRAME_INTER || self.FrameType == FRAME_KEY {
		if len(b) < n+4 {
			err = fmt.Errorf("videodata: parse invalid")
			return
		}
		self.AVCPacketType = b[n]
		n++

		self.CompositionTime = pio.I24BE(b[n:])
		n += 3
	}

	return
}

func (self Tag) videoFillHeader(b []byte) (n int) {
	flags := self.FrameType<<4 | self.CodecID
	b[n] = flags
	n++
	b[n] = self.AVCPacketType
	n++
	pio.PutI24BE(b[n:], self.CompositionTime)
	n += 3
	return
}

func (self Tag) FillHeader(b []byte) (n int) {
	switch self.Type {
	case TAG_AUDIO:
		return self.audioFillHeader(b)

	case TAG_VIDEO:
		return self.videoFillHeader(b)
	}

	return
}

func (self *Tag) ParseHeader(b []byte) (n int, err error) {
	switch self.Type {
	case TAG_AUDIO:
		return self.audioParseHeader(b)

	case TAG_VIDEO:
		return self.videoParseHeader(b)
	}

	return
}

const (
	// TypeFlagsReserved UB[5]
	// TypeFlagsAudio    UB[1] Audio tags are present
	// TypeFlagsReserved UB[1] Must be 0
	// TypeFlagsVideo    UB[1] Video tags are present
	FILE_HAS_AUDIO = 0x4
	FILE_HAS_VIDEO = 0x1
)

const TagHeaderLength = 11
const TagTrailerLength = 4

func ParseTagHeader(b []byte) (tag Tag, ts int32, datalen int, err error) {
	tagtype := b[0]

	switch tagtype {
	case TAG_AUDIO, TAG_VIDEO, TAG_SCRIPTDATA:
		tag = Tag{Type: tagtype}

	default:
		err = fmt.Errorf("flvio: ReadTag tagtype=%d invalid", tagtype)
		return
	}

	datalen = int(pio.U24BE(b[1:4]))

	var tslo uint32
	var tshi uint8
	tslo = pio.U24BE(b[4:7])
	tshi = b[7]
	ts = int32(tslo | uint32(tshi)<<24)

	return
}

func ReadTag(r io.Reader, b []byte) (tag Tag, ts int32, err error) {
	if _, err = io.ReadFull(r, b[:TagHeaderLength]); err != nil {
		return
	}
	var datalen int
	if tag, ts, datalen, err = ParseTagHeader(b); err != nil {
		return
	}

	data := make([]byte, datalen)
	if _, err = io.ReadFull(r, data); err != nil {
		return
	}

	var n int
	if n, err = (&tag).ParseHeader(data); err != nil {
		return
	}
	tag.Data = data[n:]

	if _, err = io.ReadFull(r, b[:4]); err != nil {
		return
	}
	return
}

func FillTagHeader(b []byte, tagtype uint8, datalen int, ts int32) (n int) {
	b[n] = tagtype
	n++
	pio.PutU24BE(b[n:], uint32(datalen))
	n += 3
	pio.PutU24BE(b[n:], uint32(ts&0xffffff))
	n += 3
	b[n] = uint8(ts >> 24)
	n++
	pio.PutI24BE(b[n:], 0)
	n += 3
	return
}

func FillTagTrailer(b []byte, datalen int) (n int) {
	pio.PutU32BE(b[n:], uint32(datalen+TagHeaderLength))
	n += 4
	return
}

func WriteTag(w io.Writer, tag Tag, ts int32, b []byte) (err error) {
	data := tag.Data

	n := tag.FillHeader(b[TagHeaderLength:])
	datalen := len(data) + n

	n += FillTagHeader(b, tag.Type, datalen, ts)

	if _, err = w.Write(b[:n]); err != nil {
		return
	}

	if _, err = w.Write(data); err != nil {
		return
	}

	n = FillTagTrailer(b, datalen)
	if _, err = w.Write(b[:n]); err != nil {
		return
	}

	return
}

const FileHeaderLength = 9

func FillFileHeader(b []byte, flags uint8) (n int) {
	// 'FLV', version 1
	pio.PutU32BE(b[n:], 0x464c5601)
	n += 4

	b[n] = flags
	n++

	// DataOffset: UI32 Offset in bytes from start of file to start of body (that is, size of header)
	// The DataOffset field usually has a value of 9 for FLV version 1.
	pio.PutU32BE(b[n:], 9)
	n += 4

	// PreviousTagSize0: UI32 Always 0
	pio.PutU32BE(b[n:], 0)
	n += 4

	return
}

func ParseFileHeader(b []byte) (flags uint8, skip int, err error) {
	flv := pio.U24BE(b[0:3])
	if flv != 0x464c56 { // 'FLV'
		err = fmt.Errorf("flvio: file header cc3 invalid")
		return
	}

	flags = b[4]

	skip = int(pio.U32BE(b[5:9])) - 9 + 4
	if skip < 0 {
		err = fmt.Errorf("flvio: file header datasize invalid")
		return
	}

	return
}


================================================
FILE: format/format.go
================================================
package format

import (
	"github.com/nareix/joy4/format/mp4"
	"github.com/nareix/joy4/format/ts"
	"github.com/nareix/joy4/format/rtmp"
	"github.com/nareix/joy4/format/rtsp"
	"github.com/nareix/joy4/format/flv"
	"github.com/nareix/joy4/format/aac"
	"github.com/nareix/joy4/av/avutil"
)

func RegisterAll() {
	avutil.DefaultHandlers.Add(mp4.Handler)
	avutil.DefaultHandlers.Add(ts.Handler)
	avutil.DefaultHandlers.Add(rtmp.Handler)
	avutil.DefaultHandlers.Add(rtsp.Handler)
	avutil.DefaultHandlers.Add(flv.Handler)
	avutil.DefaultHandlers.Add(aac.Handler)
}



================================================
FILE: format/mp4/demuxer.go
================================================
package mp4

import (
	"errors"
	"fmt"
	"io"
	"time"

	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/codec/aacparser"
	"github.com/nareix/joy4/codec/h264parser"
	"github.com/nareix/joy4/format/mp4/mp4io"
)

type Demuxer struct {
	r         io.ReadSeeker
	streams   []*Stream
	movieAtom *mp4io.Movie
}

func NewDemuxer(r io.ReadSeeker) *Demuxer {
	return &Demuxer{
		r: r,
	}
}

func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
	if err = self.probe(); err != nil {
		return
	}
	for _, stream := range self.streams {
		streams = append(streams, stream.CodecData)
	}
	return
}

func (self *Demuxer) readat(pos int64, b []byte) (err error) {
	if _, err = self.r.Seek(pos, 0); err != nil {
		return
	}
	if _, err = io.ReadFull(self.r, b); err != nil {
		return
	}
	return
}

func (self *Demuxer) probe() (err error) {
	if self.movieAtom != nil {
		return
	}

	var moov *mp4io.Movie
	var atoms []mp4io.Atom

	if atoms, err = mp4io.ReadFileAtoms(self.r); err != nil {
		return
	}
	if _, err = self.r.Seek(0, 0); err != nil {
		return
	}

	for _, atom := range atoms {
		if atom.Tag() == mp4io.MOOV {
			moov = atom.(*mp4io.Movie)
		}
	}

	if moov == nil {
		err = fmt.Errorf("mp4: 'moov' atom not found")
		return
	}

	self.streams = []*Stream{}
	for i, atrack := range moov.Tracks {
		stream := &Stream{
			trackAtom: atrack,
			demuxer:   self,
			idx:       i,
		}
		if atrack.Media != nil && atrack.Media.Info != nil && atrack.Media.Info.Sample != nil {
			stream.sample = atrack.Media.Info.Sample
			stream.timeScale = int64(atrack.Media.Header.TimeScale)
		} else {
			err = fmt.Errorf("mp4: sample table not found")
			return
		}

		if avc1 := atrack.GetAVC1Conf(); avc1 != nil {
			if stream.CodecData, err = h264parser.NewCodecDataFromAVCDecoderConfRecord(avc1.Data); err != nil {
				return
			}
			self.streams = append(self.streams, stream)
		} else if esds := atrack.GetElemStreamDesc(); esds != nil {
			if stream.CodecData, err = aacparser.NewCodecDataFromMPEG4AudioConfigBytes(esds.DecConfig); err != nil {
				return
			}
			self.streams = append(self.streams, stream)
		}
	}

	self.movieAtom = moov
	return
}

func (self *Stream) setSampleIndex(index int) (err error) {
	found := false
	start := 0
	self.chunkGroupIndex = 0

	for self.chunkIndex = range self.sample.ChunkOffset.Entries {
		if self.chunkGroupIndex+1 < len(self.sample.SampleToChunk.Entries) &&
			uint32(self.chunkIndex+1) == self.sample.SampleToChunk.Entries[self.chunkGroupIndex+1].FirstChunk {
			self.chunkGroupIndex++
		}
		n := int(self.sample.SampleToChunk.Entries[self.chunkGroupIndex].SamplesPerChunk)
		if index >= start && index < start+n {
			found = true
			self.sampleIndexInChunk = index - start
			break
		}
		start += n
	}
	if !found {
		err = fmt.Errorf("mp4: stream[%d]: cannot locate sample index in chunk", self.idx)
		return
	}

	if self.sample.SampleSize.SampleSize != 0 {
		self.sampleOffsetInChunk = int64(self.sampleIndexInChunk) * int64(self.sample.SampleSize.SampleSize)
	} else {
		if index >= len(self.sample.SampleSize.Entries) {
			err = fmt.Errorf("mp4: stream[%d]: sample index out of range", self.idx)
			return
		}
		self.sampleOffsetInChunk = int64(0)
		for i := index - self.sampleIndexInChunk; i < index; i++ {
			self.sampleOffsetInChunk += int64(self.sample.SampleSize.Entries[i])
		}
	}

	self.dts = int64(0)
	start = 0
	found = false
	self.sttsEntryIndex = 0
	for self.sttsEntryIndex < len(self.sample.TimeToSample.Entries) {
		entry := self.sample.TimeToSample.Entries[self.sttsEntryIndex]
		n := int(entry.Count)
		if index >= start && index < start+n {
			self.sampleIndexInSttsEntry = index - start
			self.dts += int64(index-start) * int64(entry.Duration)
			found = true
			break
		}
		start += n
		self.dts += int64(n) * int64(entry.Duration)
		self.sttsEntryIndex++
	}
	if !found {
		err = fmt.Errorf("mp4: stream[%d]: cannot locate sample index in stts entry", self.idx)
		return
	}

	if self.sample.CompositionOffset != nil && len(self.sample.CompositionOffset.Entries) > 0 {
		start = 0
		found = false
		self.cttsEntryIndex = 0
		for self.cttsEntryIndex < len(self.sample.CompositionOffset.Entries) {
			n := int(self.sample.CompositionOffset.Entries[self.cttsEntryIndex].Count)
			if index >= start && index < start+n {
				self.sampleIndexInCttsEntry = index - start
				found = true
				break
			}
			start += n
			self.cttsEntryIndex++
		}
		if !found {
			err = fmt.Errorf("mp4: stream[%d]: cannot locate sample index in ctts entry", self.idx)
			return
		}
	}

	if self.sample.SyncSample != nil {
		self.syncSampleIndex = 0
		for self.syncSampleIndex < len(self.sample.SyncSample.Entries)-1 {
			if self.sample.SyncSample.Entries[self.syncSampleIndex+1]-1 > uint32(index) {
				break
			}
			self.syncSampleIndex++
		}
	}

	if false {
		fmt.Printf("mp4: stream[%d]: setSampleIndex chunkGroupIndex=%d chunkIndex=%d sampleOffsetInChunk=%d\n",
			self.idx, self.chunkGroupIndex, self.chunkIndex, self.sampleOffsetInChunk)
	}

	self.sampleIndex = index
	return
}

func (self *Stream) isSampleValid() bool {
	if self.chunkIndex >= len(self.sample.ChunkOffset.Entries) {
		return false
	}
	if self.chunkGroupIndex >= len(self.sample.SampleToChunk.Entries) {
		return false
	}
	if self.sttsEntryIndex >= len(self.sample.TimeToSample.Entries) {
		return false
	}
	if self.sample.CompositionOffset != nil && len(self.sample.CompositionOffset.Entries) > 0 {
		if self.cttsEntryIndex >= len(self.sample.CompositionOffset.Entries) {
			return false
		}
	}
	if self.sample.SyncSample != nil {
		if self.syncSampleIndex >= len(self.sample.SyncSample.Entries) {
			return false
		}
	}
	if self.sample.SampleSize.SampleSize != 0 {
		if self.sampleIndex >= len(self.sample.SampleSize.Entries) {
			return false
		}
	}
	return true
}

func (self *Stream) incSampleIndex() (duration int64) {
	if false {
		fmt.Printf("incSampleIndex sampleIndex=%d sampleOffsetInChunk=%d sampleIndexInChunk=%d chunkGroupIndex=%d chunkIndex=%d\n",
			self.sampleIndex, self.sampleOffsetInChunk, self.sampleIndexInChunk, self.chunkGroupIndex, self.chunkIndex)
	}

	self.sampleIndexInChunk++
	if uint32(self.sampleIndexInChunk) == self.sample.SampleToChunk.Entries[self.chunkGroupIndex].SamplesPerChunk {
		self.chunkIndex++
		self.sampleIndexInChunk = 0
		self.sampleOffsetInChunk = int64(0)
	} else {
		if self.sample.SampleSize.SampleSize != 0 {
			self.sampleOffsetInChunk += int64(self.sample.SampleSize.SampleSize)
		} else {
			self.sampleOffsetInChunk += int64(self.sample.SampleSize.Entries[self.sampleIndex])
		}
	}

	if self.chunkGroupIndex+1 < len(self.sample.SampleToChunk.Entries) &&
		uint32(self.chunkIndex+1) == self.sample.SampleToChunk.Entries[self.chunkGroupIndex+1].FirstChunk {
		self.chunkGroupIndex++
	}

	sttsEntry := self.sample.TimeToSample.Entries[self.sttsEntryIndex]
	duration = int64(sttsEntry.Duration)
	self.sampleIndexInSttsEntry++
	self.dts += duration
	if uint32(self.sampleIndexInSttsEntry) == sttsEntry.Count {
		self.sampleIndexInSttsEntry = 0
		self.sttsEntryIndex++
	}

	if self.sample.CompositionOffset != nil && len(self.sample.CompositionOffset.Entries) > 0 {
		self.sampleIndexInCttsEntry++
		if uint32(self.sampleIndexInCttsEntry) == self.sample.CompositionOffset.Entries[self.cttsEntryIndex].Count {
			self.sampleIndexInCttsEntry = 0
			self.cttsEntryIndex++
		}
	}

	if self.sample.SyncSample != nil {
		entries := self.sample.SyncSample.Entries
		if self.syncSampleIndex+1 < len(entries) && entries[self.syncSampleIndex+1]-1 == uint32(self.sampleIndex+1) {
			self.syncSampleIndex++
		}
	}

	self.sampleIndex++
	return
}

func (self *Stream) sampleCount() int {
	if self.sample.SampleSize.SampleSize == 0 {
		chunkGroupIndex := 0
		count := 0
		for chunkIndex := range self.sample.ChunkOffset.Entries {
			n := int(self.sample.SampleToChunk.Entries[chunkGroupIndex].SamplesPerChunk)
			count += n
			if chunkGroupIndex+1 < len(self.sample.SampleToChunk.Entries) &&
				uint32(chunkIndex+1) == self.sample.SampleToChunk.Entries[chunkGroupIndex+1].FirstChunk {
				chunkGroupIndex++
			}
		}
		return count
	} else {
		return len(self.sample.SampleSize.Entries)
	}
}

func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
	if err = self.probe(); err != nil {
		return
	}
	if len(self.streams) == 0 {
		err = errors.New("mp4: no streams available while trying to read a packet")
		return
	}

	var chosen *Stream
	var chosenidx int
	for i, stream := range self.streams {
		if chosen == nil || stream.tsToTime(stream.dts) < chosen.tsToTime(chosen.dts) {
			chosen = stream
			chosenidx = i
		}
	}
	if false {
		fmt.Printf("ReadPacket: chosen index=%v time=%v\n", chosen.idx, chosen.tsToTime(chosen.dts))
	}
	tm := chosen.tsToTime(chosen.dts)
	if pkt, err = chosen.readPacket(); err != nil {
		return
	}
	pkt.Time = tm
	pkt.Idx = int8(chosenidx)
	return
}

func (self *Demuxer) CurrentTime() (tm time.Duration) {
	if len(self.streams) > 0 {
		stream := self.streams[0]
		tm = stream.tsToTime(stream.dts)
	}
	return
}

func (self *Demuxer) SeekToTime(tm time.Duration) (err error) {
	for _, stream := range self.streams {
		if stream.Type().IsVideo() {
			if err = stream.seekToTime(tm); err != nil {
				return
			}
			tm = stream.tsToTime(stream.dts)
			break
		}
	}

	for _, stream := range self.streams {
		if !stream.Type().IsVideo() {
			if err = stream.seekToTime(tm); err != nil {
				return
			}
		}
	}

	return
}

func (self *Stream) readPacket() (pkt av.Packet, err error) {
	if !self.isSampleValid() {
		err = io.EOF
		return
	}
	//fmt.Println("readPacket", self.sampleIndex)

	chunkOffset := self.sample.ChunkOffset.Entries[self.chunkIndex]
	sampleSize := uint32(0)
	if self.sample.SampleSize.SampleSize != 0 {
		sampleSize = self.sample.SampleSize.SampleSize
	} else {
		sampleSize = self.sample.SampleSize.Entries[self.sampleIndex]
	}

	sampleOffset := int64(chunkOffset) + self.sampleOffsetInChunk
	pkt.Data = make([]byte, sampleSize)
	if err = self.demuxer.readat(sampleOffset, pkt.Data); err != nil {
		return
	}

	if self.sample.SyncSample != nil {
		if self.sample.SyncSample.Entries[self.syncSampleIndex]-1 == uint32(self.sampleIndex) {
			pkt.IsKeyFrame = true
		}
	}

	//println("pts/dts", self.ptsEntryIndex, self.dtsEntryIndex)
	if self.sample.CompositionOffset != nil && len(self.sample.CompositionOffset.Entries) > 0 {
		cts := int64(self.sample.CompositionOffset.Entries[self.cttsEntryIndex].Offset)
		pkt.CompositionTime = self.tsToTime(cts)
	}

	self.incSampleIndex()

	return
}

func (self *Stream) seekToTime(tm time.Duration) (err error) {
	index := self.timeToSampleIndex(tm)
	if err = self.setSampleIndex(index); err != nil {
		return
	}
	if false {
		fmt.Printf("stream[%d]: seekToTime index=%v time=%v cur=%v\n", self.idx, index, tm, self.tsToTime(self.dts))
	}
	return
}

func (self *Stream) timeToSampleIndex(tm time.Duration) int {
	targetTs := self.timeToTs(tm)
	targetIndex := 0

	startTs := int64(0)
	endTs := int64(0)
	startIndex := 0
	endIndex := 0
	found := false
	for _, entry := range self.sample.TimeToSample.Entries {
		endTs = startTs + int64(entry.Count*entry.Duration)
		endIndex = startIndex + int(entry.Count)
		if targetTs >= startTs && targetTs < endTs {
			targetIndex = startIndex + int((targetTs-startTs)/int64(entry.Duration))
			found = true
		}
		startTs = endTs
		startIndex = endIndex
	}
	if !found {
		if targetTs < 0 {
			targetIndex = 0
		} else {
			targetIndex = endIndex - 1
		}
	}

	if self.sample.SyncSample != nil {
		entries := self.sample.SyncSample.Entries
		for i := len(entries) - 1; i >= 0; i-- {
			if entries[i]-1 < uint32(targetIndex) {
				targetIndex = int(entries[i] - 1)
				break
			}
		}
	}

	return targetIndex
}


================================================
FILE: format/mp4/handler.go
================================================
package mp4

import (
	"io"
	"github.com/nareix/joy4/av"
	"github.com/nareix/joy4/av/avutil"
)

var CodecTypes = []av.CodecType{av.H264, av.AAC}

func Handler(h *avutil.RegisterHandler) {
	h.Ext = ".mp4"

	h.Probe = func(b []byte) bool {
		switch string(b[4:8]) {
		case "moov","ftyp","free","mdat","moof":
			return true
		}
		return false
	}

	h.ReaderDemuxer = func(r io.Reader) av.Demuxer {
		return NewDemuxer(r.(io.ReadSeeker))
	}

	h.WriterMuxer = func(w io.Writer) av.Muxer {
		return NewMuxer(w.(io.WriteSeeker))
	}

	h.CodecTypes = CodecTypes
}



================================================
FILE: format/mp4/mp4io/atoms.go
================================================
package mp4io

import "github.com/nareix/joy4/utils/bits/pio"
import "time"

const MOOF = Tag(0x6d6f6f66)

func (self MovieFrag) Tag() Tag {
	return MOOF
}

const HDLR = Tag(0x68646c72)

func (self HandlerRefer) Tag() Tag {
	return HDLR
}

const AVC1 = Tag(0x61766331)

func (self AVC1Desc) Tag() Tag {
	return AVC1
}

const URL  = Tag(0x75726c20)

func (self DataReferUrl) Tag() Tag {
	return URL
}

const TREX = Tag(0x74726578)

func (self TrackExtend) Tag() Tag {
	return TREX
}

const ESDS = Tag(0x65736473)

func (self ElemStreamDesc) Tag() Tag {
	return ESDS
}

const MDHD = Tag(0x6d646864)

func (self MediaHeader) Tag() Tag {
	return MDHD
}

const STTS = Tag(0x73747473)

func (self TimeToSample) Tag() Tag {
	return STTS
}

const STSS = Tag(0x73747373)

func (self SyncSample) Tag() Tag {
	return STSS
}

const MFHD = Tag(0x6d666864)

func (self MovieFragHeader) Tag() Tag {
	return MFHD
}

const MVHD = Tag(0x6d766864)

func (self MovieHeader) Tag() Tag {
	return MVHD
}

const MINF = Tag(0x6d696e66)

func (self MediaInfo) Tag() Tag {
	return MINF
}

const MOOV = Tag(0x6d6f6f76)

func (self Movie) Tag() Tag {
	return MOOV
}

const MVEX = Tag(0x6d766578)

func (self MovieExtend) Tag() Tag {
	return MVEX
}

const STSD = Tag(0x73747364)

func (self SampleDesc) Tag() Tag {
	return STSD
}

const MP4A = Tag(0x6d703461)

func (self MP4ADesc) Tag() Tag {
	return MP4A
}

const CTTS = Tag(0x63747473)

func (self CompositionOffset) Tag() Tag {
	return CTTS
}

const STCO = Tag(0x7374636f)

func (self ChunkOffset) Tag() Tag {
	return STCO
}

const TRUN = Tag(0x7472756e)

func (self TrackFragRun) Tag() Tag {
	return TRUN
}

const TRAK = Tag(0x7472616b)

func (self Track) Tag() Tag {
	return TRAK
}

const MDIA = Tag(0x6d646961)

func (self Media) Tag() Tag {
	return MDIA
}

const STSC = Tag(0x73747363)

func (self SampleToChunk) Tag() Tag {
	return STSC
}

const VMHD = Tag(0x766d6864)

func (self VideoMediaInfo) Tag() Tag {
	return VMHD
}

const STBL = Tag(0x7374626c)

func (self SampleTable) Tag() Tag {
	return STBL
}

const AVCC = Tag(0x61766343)

func (self AVC1Conf) Tag() Tag {
	return AVCC
}

const TFDT = Tag(0x74666474)

func (self TrackFragDecodeTime) Tag() Tag {
	return TFDT
}

const DINF = Tag(0x64696e66)

func (self DataInfo) Tag() Tag {
	return DINF
}

const DREF = Tag(0x64726566)

func (self DataRefer) Tag() Tag {
	return DREF
}

const TRAF = Tag(0x74726166)

func (self TrackFrag) Tag() Tag {
	return TRAF
}

const STSZ = Tag(0x7374737a)

func (self SampleSize) Tag() Tag {
	return STSZ
}

const TFHD = Tag(0x74666864)

func (self TrackFragHeader) Tag() Tag {
	return TFHD
}

const TKHD = Tag(0x746b6864)

func (self TrackHeader) Tag() Tag {
	return TKHD
}

const SMHD = Tag(0x736d6864)

func (self SoundMediaInfo) Tag() Tag {
	return SMHD
}

const MDAT = Tag(0x6d646174)

type Movie struct {
	Header		*MovieHeader
	MovieExtend	*MovieExtend
	Tracks		[]*Track
	Unknowns	[]Atom
	AtomPos
}

func (self Movie) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(MOOV))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self Movie) marshal(b []byte) (n int) {
	if self.Header != nil {
		n += self.Header.Marshal(b[n:])
	}
	if self.MovieExtend != nil {
		n += self.MovieExtend.Marshal(b[n:])
	}
	for _, atom := range self.Tracks {
		n += atom.Marshal(b[n:])
	}
	for _, atom := range self.Unknowns {
		n += atom.Marshal(b[n:])
	}
	return
}
func (self Movie) Len() (n int) {
	n += 8
	if self.Header != nil {
		n += self.Header.Len()
	}
	if self.MovieExtend != nil {
		n += self.MovieExtend.Len()
	}
	for _, atom := range self.Tracks {
		n += atom.Len()
	}
	for _, atom := range self.Unknowns {
		n += atom.Len()
	}
	return
}
func (self *Movie) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	for n+8 < len(b) {
		tag := Tag(pio.U32BE(b[n+4:]))
		size := int(pio.U32BE(b[n:]))
		if len(b) < n+size {
			err = parseErr("TagSizeInvalid", n+offset, err)
			return
		}
		switch tag {
		case MVHD:
			{
				atom := &MovieHeader{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("mvhd", n+offset, err)
					return
				}
				self.Header = atom
			}
		case MVEX:
			{
				atom := &MovieExtend{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("mvex", n+offset, err)
					return
				}
				self.MovieExtend = atom
			}
		case TRAK:
			{
				atom := &Track{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("trak", n+offset, err)
					return
				}
				self.Tracks = append(self.Tracks, atom)
			}
		default:
			{
				atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("", n+offset, err)
					return
				}
				self.Unknowns = append(self.Unknowns, atom)
			}
		}
		n += size
	}
	return
}
func (self Movie) Children() (r []Atom) {
	if self.Header != nil {
		r = append(r, self.Header)
	}
	if self.MovieExtend != nil {
		r = append(r, self.MovieExtend)
	}
	for _, atom := range self.Tracks {
		r = append(r, atom)
	}
	r = append(r, self.Unknowns...)
	return
}

type MovieHeader struct {
	Version			uint8
	Flags			uint32
	CreateTime		time.Time
	ModifyTime		time.Time
	TimeScale		int32
	Duration		int32
	PreferredRate		float64
	PreferredVolume		float64
	Matrix			[9]int32
	PreviewTime		time.Time
	PreviewDuration		time.Time
	PosterTime		time.Time
	SelectionTime		time.Time
	SelectionDuration	time.Time
	CurrentTime		time.Time
	NextTrackId		int32
	AtomPos
}

func (self MovieHeader) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(MVHD))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self MovieHeader) marshal(b []byte) (n int) {
	pio.PutU8(b[n:], self.Version)
	n += 1
	pio.PutU24BE(b[n:], self.Flags)
	n += 3
	PutTime32(b[n:], self.CreateTime)
	n += 4
	PutTime32(b[n:], self.ModifyTime)
	n += 4
	pio.PutI32BE(b[n:], self.TimeScale)
	n += 4
	pio.PutI32BE(b[n:], self.Duration)
	n += 4
	PutFixed32(b[n:], self.PreferredRate)
	n += 4
	PutFixed16(b[n:], self.PreferredVolume)
	n += 2
	n += 10
	for _, entry := range self.Matrix {
		pio.PutI32BE(b[n:], entry)
		n += 4
	}
	PutTime32(b[n:], self.PreviewTime)
	n += 4
	PutTime32(b[n:], self.PreviewDuration)
	n += 4
	PutTime32(b[n:], self.PosterTime)
	n += 4
	PutTime32(b[n:], self.SelectionTime)
	n += 4
	PutTime32(b[n:], self.SelectionDuration)
	n += 4
	PutTime32(b[n:], self.CurrentTime)
	n += 4
	pio.PutI32BE(b[n:], self.NextTrackId)
	n += 4
	return
}
func (self MovieHeader) Len() (n int) {
	n += 8
	n += 1
	n += 3
	n += 4
	n += 4
	n += 4
	n += 4
	n += 4
	n += 2
	n += 10
	n += 4*len(self.Matrix[:])
	n += 4
	n += 4
	n += 4
	n += 4
	n += 4
	n += 4
	n += 4
	return
}
func (self *MovieHeader) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	if len(b) < n+1 {
		err = parseErr("Version", n+offset, err)
		return
	}
	self.Version = pio.U8(b[n:])
	n += 1
	if len(b) < n+3 {
		err = parseErr("Flags", n+offset, err)
		return
	}
	self.Flags = pio.U24BE(b[n:])
	n += 3
	if len(b) < n+4 {
		err = parseErr("CreateTime", n+offset, err)
		return
	}
	self.CreateTime = GetTime32(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("ModifyTime", n+offset, err)
		return
	}
	self.ModifyTime = GetTime32(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("TimeScale", n+offset, err)
		return
	}
	self.TimeScale = pio.I32BE(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("Duration", n+offset, err)
		return
	}
	self.Duration = pio.I32BE(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("PreferredRate", n+offset, err)
		return
	}
	self.PreferredRate = GetFixed32(b[n:])
	n += 4
	if len(b) < n+2 {
		err = parseErr("PreferredVolume", n+offset, err)
		return
	}
	self.PreferredVolume = GetFixed16(b[n:])
	n += 2
	n += 10
	if len(b) < n+4*len(self.Matrix) {
		err = parseErr("Matrix", n+offset, err)
		return
	}
	for i := range self.Matrix {
		self.Matrix[i] = pio.I32BE(b[n:])
		n += 4
	}
	if len(b) < n+4 {
		err = parseErr("PreviewTime", n+offset, err)
		return
	}
	self.PreviewTime = GetTime32(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("PreviewDuration", n+offset, err)
		return
	}
	self.PreviewDuration = GetTime32(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("PosterTime", n+offset, err)
		return
	}
	self.PosterTime = GetTime32(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("SelectionTime", n+offset, err)
		return
	}
	self.SelectionTime = GetTime32(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("SelectionDuration", n+offset, err)
		return
	}
	self.SelectionDuration = GetTime32(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("CurrentTime", n+offset, err)
		return
	}
	self.CurrentTime = GetTime32(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("NextTrackId", n+offset, err)
		return
	}
	self.NextTrackId = pio.I32BE(b[n:])
	n += 4
	return
}
func (self MovieHeader) Children() (r []Atom) {
	return
}

type Track struct {
	Header		*TrackHeader
	Media		*Media
	Unknowns	[]Atom
	AtomPos
}

func (self Track) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(TRAK))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self Track) marshal(b []byte) (n int) {
	if self.Header != nil {
		n += self.Header.Marshal(b[n:])
	}
	if self.Media != nil {
		n += self.Media.Marshal(b[n:])
	}
	for _, atom := range self.Unknowns {
		n += atom.Marshal(b[n:])
	}
	return
}
func (self Track) Len() (n int) {
	n += 8
	if self.Header != nil {
		n += self.Header.Len()
	}
	if self.Media != nil {
		n += self.Media.Len()
	}
	for _, atom := range self.Unknowns {
		n += atom.Len()
	}
	return
}
func (self *Track) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	for n+8 < len(b) {
		tag := Tag(pio.U32BE(b[n+4:]))
		size := int(pio.U32BE(b[n:]))
		if len(b) < n+size {
			err = parseErr("TagSizeInvalid", n+offset, err)
			return
		}
		switch tag {
		case TKHD:
			{
				atom := &TrackHeader{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("tkhd", n+offset, err)
					return
				}
				self.Header = atom
			}
		case MDIA:
			{
				atom := &Media{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("mdia", n+offset, err)
					return
				}
				self.Media = atom
			}
		default:
			{
				atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("", n+offset, err)
					return
				}
				self.Unknowns = append(self.Unknowns, atom)
			}
		}
		n += size
	}
	return
}
func (self Track) Children() (r []Atom) {
	if self.Header != nil {
		r = append(r, self.Header)
	}
	if self.Media != nil {
		r = append(r, self.Media)
	}
	r = append(r, self.Unknowns...)
	return
}

type TrackHeader struct {
	Version		uint8
	Flags		uint32
	CreateTime	time.Time
	ModifyTime	time.Time
	TrackId		int32
	Duration	int32
	Layer		int16
	AlternateGroup	int16
	Volume		float64
	Matrix		[9]int32
	TrackWidth	float64
	TrackHeight	float64
	AtomPos
}

func (self TrackHeader) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(TKHD))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self TrackHeader) marshal(b []byte) (n int) {
	pio.PutU8(b[n:], self.Version)
	n += 1
	pio.PutU24BE(b[n:], self.Flags)
	n += 3
	PutTime32(b[n:], self.CreateTime)
	n += 4
	PutTime32(b[n:], self.ModifyTime)
	n += 4
	pio.PutI32BE(b[n:], self.TrackId)
	n += 4
	n += 4
	pio.PutI32BE(b[n:], self.Duration)
	n += 4
	n += 8
	pio.PutI16BE(b[n:], self.Layer)
	n += 2
	pio.PutI16BE(b[n:], self.AlternateGroup)
	n += 2
	PutFixed16(b[n:], self.Volume)
	n += 2
	n += 2
	for _, entry := range self.Matrix {
		pio.PutI32BE(b[n:], entry)
		n += 4
	}
	PutFixed32(b[n:], self.TrackWidth)
	n += 4
	PutFixed32(b[n:], self.TrackHeight)
	n += 4
	return
}
func (self TrackHeader) Len() (n int) {
	n += 8
	n += 1
	n += 3
	n += 4
	n += 4
	n += 4
	n += 4
	n += 4
	n += 8
	n += 2
	n += 2
	n += 2
	n += 2
	n += 4*len(self.Matrix[:])
	n += 4
	n += 4
	return
}
func (self *TrackHeader) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	if len(b) < n+1 {
		err = parseErr("Version", n+offset, err)
		return
	}
	self.Version = pio.U8(b[n:])
	n += 1
	if len(b) < n+3 {
		err = parseErr("Flags", n+offset, err)
		return
	}
	self.Flags = pio.U24BE(b[n:])
	n += 3
	if len(b) < n+4 {
		err = parseErr("CreateTime", n+offset, err)
		return
	}
	self.CreateTime = GetTime32(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("ModifyTime", n+offset, err)
		return
	}
	self.ModifyTime = GetTime32(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("TrackId", n+offset, err)
		return
	}
	self.TrackId = pio.I32BE(b[n:])
	n += 4
	n += 4
	if len(b) < n+4 {
		err = parseErr("Duration", n+offset, err)
		return
	}
	self.Duration = pio.I32BE(b[n:])
	n += 4
	n += 8
	if len(b) < n+2 {
		err = parseErr("Layer", n+offset, err)
		return
	}
	self.Layer = pio.I16BE(b[n:])
	n += 2
	if len(b) < n+2 {
		err = parseErr("AlternateGroup", n+offset, err)
		return
	}
	self.AlternateGroup = pio.I16BE(b[n:])
	n += 2
	if len(b) < n+2 {
		err = parseErr("Volume", n+offset, err)
		return
	}
	self.Volume = GetFixed16(b[n:])
	n += 2
	n += 2
	if len(b) < n+4*len(self.Matrix) {
		err = parseErr("Matrix", n+offset, err)
		return
	}
	for i := range self.Matrix {
		self.Matrix[i] = pio.I32BE(b[n:])
		n += 4
	}
	if len(b) < n+4 {
		err = parseErr("TrackWidth", n+offset, err)
		return
	}
	self.TrackWidth = GetFixed32(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("TrackHeight", n+offset, err)
		return
	}
	self.TrackHeight = GetFixed32(b[n:])
	n += 4
	return
}
func (self TrackHeader) Children() (r []Atom) {
	return
}

type HandlerRefer struct {
	Version	uint8
	Flags	uint32
	Type	[4]byte
	SubType	[4]byte
	Name	[]byte
	AtomPos
}

func (self HandlerRefer) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(HDLR))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self HandlerRefer) marshal(b []byte) (n int) {
	pio.PutU8(b[n:], self.Version)
	n += 1
	pio.PutU24BE(b[n:], self.Flags)
	n += 3
	copy(b[n:], self.Type[:])
	n += len(self.Type[:])
	copy(b[n:], self.SubType[:])
	n += len(self.SubType[:])
	copy(b[n:], self.Name[:])
	n += len(self.Name[:])
	return
}
func (self HandlerRefer) Len() (n int) {
	n += 8
	n += 1
	n += 3
	n += len(self.Type[:])
	n += len(self.SubType[:])
	n += len(self.Name[:])
	return
}
func (self *HandlerRefer) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	if len(b) < n+1 {
		err = parseErr("Version", n+offset, err)
		return
	}
	self.Version = pio.U8(b[n:])
	n += 1
	if len(b) < n+3 {
		err = parseErr("Flags", n+offset, err)
		return
	}
	self.Flags = pio.U24BE(b[n:])
	n += 3
	if len(b) < n+len(self.Type) {
		err = parseErr("Type", n+offset, err)
		return
	}
	copy(self.Type[:], b[n:])
	n += len(self.Type)
	if len(b) < n+len(self.SubType) {
		err = parseErr("SubType", n+offset, err)
		return
	}
	copy(self.SubType[:], b[n:])
	n += len(self.SubType)
	self.Name = b[n:]
	n += len(b[n:])
	return
}
func (self HandlerRefer) Children() (r []Atom) {
	return
}

type Media struct {
	Header		*MediaHeader
	Handler		*HandlerRefer
	Info		*MediaInfo
	Unknowns	[]Atom
	AtomPos
}

func (self Media) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(MDIA))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self Media) marshal(b []byte) (n int) {
	if self.Header != nil {
		n += self.Header.Marshal(b[n:])
	}
	if self.Handler != nil {
		n += self.Handler.Marshal(b[n:])
	}
	if self.Info != nil {
		n += self.Info.Marshal(b[n:])
	}
	for _, atom := range self.Unknowns {
		n += atom.Marshal(b[n:])
	}
	return
}
func (self Media) Len() (n int) {
	n += 8
	if self.Header != nil {
		n += self.Header.Len()
	}
	if self.Handler != nil {
		n += self.Handler.Len()
	}
	if self.Info != nil {
		n += self.Info.Len()
	}
	for _, atom := range self.Unknowns {
		n += atom.Len()
	}
	return
}
func (self *Media) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	for n+8 < len(b) {
		tag := Tag(pio.U32BE(b[n+4:]))
		size := int(pio.U32BE(b[n:]))
		if len(b) < n+size {
			err = parseErr("TagSizeInvalid", n+offset, err)
			return
		}
		switch tag {
		case MDHD:
			{
				atom := &MediaHeader{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("mdhd", n+offset, err)
					return
				}
				self.Header = atom
			}
		case HDLR:
			{
				atom := &HandlerRefer{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("hdlr", n+offset, err)
					return
				}
				self.Handler = atom
			}
		case MINF:
			{
				atom := &MediaInfo{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("minf", n+offset, err)
					return
				}
				self.Info = atom
			}
		default:
			{
				atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("", n+offset, err)
					return
				}
				self.Unknowns = append(self.Unknowns, atom)
			}
		}
		n += size
	}
	return
}
func (self Media) Children() (r []Atom) {
	if self.Header != nil {
		r = append(r, self.Header)
	}
	if self.Handler != nil {
		r = append(r, self.Handler)
	}
	if self.Info != nil {
		r = append(r, self.Info)
	}
	r = append(r, self.Unknowns...)
	return
}

type MediaHeader struct {
	Version		uint8
	Flags		uint32
	CreateTime	time.Time
	ModifyTime	time.Time
	TimeScale	int32
	Duration	int32
	Language	int16
	Quality		int16
	AtomPos
}

func (self MediaHeader) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(MDHD))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self MediaHeader) marshal(b []byte) (n int) {
	pio.PutU8(b[n:], self.Version)
	n += 1
	pio.PutU24BE(b[n:], self.Flags)
	n += 3
	PutTime32(b[n:], self.CreateTime)
	n += 4
	PutTime32(b[n:], self.ModifyTime)
	n += 4
	pio.PutI32BE(b[n:], self.TimeScale)
	n += 4
	pio.PutI32BE(b[n:], self.Duration)
	n += 4
	pio.PutI16BE(b[n:], self.Language)
	n += 2
	pio.PutI16BE(b[n:], self.Quality)
	n += 2
	return
}
func (self MediaHeader) Len() (n int) {
	n += 8
	n += 1
	n += 3
	n += 4
	n += 4
	n += 4
	n += 4
	n += 2
	n += 2
	return
}
func (self *MediaHeader) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	if len(b) < n+1 {
		err = parseErr("Version", n+offset, err)
		return
	}
	self.Version = pio.U8(b[n:])
	n += 1
	if len(b) < n+3 {
		err = parseErr("Flags", n+offset, err)
		return
	}
	self.Flags = pio.U24BE(b[n:])
	n += 3
	if len(b) < n+4 {
		err = parseErr("CreateTime", n+offset, err)
		return
	}
	self.CreateTime = GetTime32(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("ModifyTime", n+offset, err)
		return
	}
	self.ModifyTime = GetTime32(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("TimeScale", n+offset, err)
		return
	}
	self.TimeScale = pio.I32BE(b[n:])
	n += 4
	if len(b) < n+4 {
		err = parseErr("Duration", n+offset, err)
		return
	}
	self.Duration = pio.I32BE(b[n:])
	n += 4
	if len(b) < n+2 {
		err = parseErr("Language", n+offset, err)
		return
	}
	self.Language = pio.I16BE(b[n:])
	n += 2
	if len(b) < n+2 {
		err = parseErr("Quality", n+offset, err)
		return
	}
	self.Quality = pio.I16BE(b[n:])
	n += 2
	return
}
func (self MediaHeader) Children() (r []Atom) {
	return
}

type MediaInfo struct {
	Sound		*SoundMediaInfo
	Video		*VideoMediaInfo
	Data		*DataInfo
	Sample		*SampleTable
	Unknowns	[]Atom
	AtomPos
}

func (self MediaInfo) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(MINF))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self MediaInfo) marshal(b []byte) (n int) {
	if self.Sound != nil {
		n += self.Sound.Marshal(b[n:])
	}
	if self.Video != nil {
		n += self.Video.Marshal(b[n:])
	}
	if self.Data != nil {
		n += self.Data.Marshal(b[n:])
	}
	if self.Sample != nil {
		n += self.Sample.Marshal(b[n:])
	}
	for _, atom := range self.Unknowns {
		n += atom.Marshal(b[n:])
	}
	return
}
func (self MediaInfo) Len() (n int) {
	n += 8
	if self.Sound != nil {
		n += self.Sound.Len()
	}
	if self.Video != nil {
		n += self.Video.Len()
	}
	if self.Data != nil {
		n += self.Data.Len()
	}
	if self.Sample != nil {
		n += self.Sample.Len()
	}
	for _, atom := range self.Unknowns {
		n += atom.Len()
	}
	return
}
func (self *MediaInfo) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	for n+8 < len(b) {
		tag := Tag(pio.U32BE(b[n+4:]))
		size := int(pio.U32BE(b[n:]))
		if len(b) < n+size {
			err = parseErr("TagSizeInvalid", n+offset, err)
			return
		}
		switch tag {
		case SMHD:
			{
				atom := &SoundMediaInfo{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("smhd", n+offset, err)
					return
				}
				self.Sound = atom
			}
		case VMHD:
			{
				atom := &VideoMediaInfo{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("vmhd", n+offset, err)
					return
				}
				self.Video = atom
			}
		case DINF:
			{
				atom := &DataInfo{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("dinf", n+offset, err)
					return
				}
				self.Data = atom
			}
		case STBL:
			{
				atom := &SampleTable{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("stbl", n+offset, err)
					return
				}
				self.Sample = atom
			}
		default:
			{
				atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("", n+offset, err)
					return
				}
				self.Unknowns = append(self.Unknowns, atom)
			}
		}
		n += size
	}
	return
}
func (self MediaInfo) Children() (r []Atom) {
	if self.Sound != nil {
		r = append(r, self.Sound)
	}
	if self.Video != nil {
		r = append(r, self.Video)
	}
	if self.Data != nil {
		r = append(r, self.Data)
	}
	if self.Sample != nil {
		r = append(r, self.Sample)
	}
	r = append(r, self.Unknowns...)
	return
}

type DataInfo struct {
	Refer		*DataRefer
	Unknowns	[]Atom
	AtomPos
}

func (self DataInfo) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(DINF))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self DataInfo) marshal(b []byte) (n int) {
	if self.Refer != nil {
		n += self.Refer.Marshal(b[n:])
	}
	for _, atom := range self.Unknowns {
		n += atom.Marshal(b[n:])
	}
	return
}
func (self DataInfo) Len() (n int) {
	n += 8
	if self.Refer != nil {
		n += self.Refer.Len()
	}
	for _, atom := range self.Unknowns {
		n += atom.Len()
	}
	return
}
func (self *DataInfo) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	for n+8 < len(b) {
		tag := Tag(pio.U32BE(b[n+4:]))
		size := int(pio.U32BE(b[n:]))
		if len(b) < n+size {
			err = parseErr("TagSizeInvalid", n+offset, err)
			return
		}
		switch tag {
		case DREF:
			{
				atom := &DataRefer{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("dref", n+offset, err)
					return
				}
				self.Refer = atom
			}
		default:
			{
				atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("", n+offset, err)
					return
				}
				self.Unknowns = append(self.Unknowns, atom)
			}
		}
		n += size
	}
	return
}
func (self DataInfo) Children() (r []Atom) {
	if self.Refer != nil {
		r = append(r, self.Refer)
	}
	r = append(r, self.Unknowns...)
	return
}

type DataRefer struct {
	Version	uint8
	Flags	uint32
	Url	*DataReferUrl
	AtomPos
}

func (self DataRefer) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(DREF))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self DataRefer) marshal(b []byte) (n int) {
	pio.PutU8(b[n:], self.Version)
	n += 1
	pio.PutU24BE(b[n:], self.Flags)
	n += 3
	_childrenNR := 0
	if self.Url != nil {
		_childrenNR++
	}
	pio.PutI32BE(b[n:], int32(_childrenNR))
	n += 4
	if self.Url != nil {
		n += self.Url.Marshal(b[n:])
	}
	return
}
func (self DataRefer) Len() (n int) {
	n += 8
	n += 1
	n += 3
	n += 4
	if self.Url != nil {
		n += self.Url.Len()
	}
	return
}
func (self *DataRefer) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	if len(b) < n+1 {
		err = parseErr("Version", n+offset, err)
		return
	}
	self.Version = pio.U8(b[n:])
	n += 1
	if len(b) < n+3 {
		err = parseErr("Flags", n+offset, err)
		return
	}
	self.Flags = pio.U24BE(b[n:])
	n += 3
	n += 4
	for n+8 < len(b) {
		tag := Tag(pio.U32BE(b[n+4:]))
		size := int(pio.U32BE(b[n:]))
		if len(b) < n+size {
			err = parseErr("TagSizeInvalid", n+offset, err)
			return
		}
		switch tag {
		case URL :
			{
				atom := &DataReferUrl{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("url ", n+offset, err)
					return
				}
				self.Url = atom
			}
		}
		n += size
	}
	return
}
func (self DataRefer) Children() (r []Atom) {
	if self.Url != nil {
		r = append(r, self.Url)
	}
	return
}

type DataReferUrl struct {
	Version	uint8
	Flags	uint32
	AtomPos
}

func (self DataReferUrl) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(URL ))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self DataReferUrl) marshal(b []byte) (n int) {
	pio.PutU8(b[n:], self.Version)
	n += 1
	pio.PutU24BE(b[n:], self.Flags)
	n += 3
	return
}
func (self DataReferUrl) Len() (n int) {
	n += 8
	n += 1
	n += 3
	return
}
func (self *DataReferUrl) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	if len(b) < n+1 {
		err = parseErr("Version", n+offset, err)
		return
	}
	self.Version = pio.U8(b[n:])
	n += 1
	if len(b) < n+3 {
		err = parseErr("Flags", n+offset, err)
		return
	}
	self.Flags = pio.U24BE(b[n:])
	n += 3
	return
}
func (self DataReferUrl) Children() (r []Atom) {
	return
}

type SoundMediaInfo struct {
	Version	uint8
	Flags	uint32
	Balance	int16
	AtomPos
}

func (self SoundMediaInfo) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(SMHD))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self SoundMediaInfo) marshal(b []byte) (n int) {
	pio.PutU8(b[n:], self.Version)
	n += 1
	pio.PutU24BE(b[n:], self.Flags)
	n += 3
	pio.PutI16BE(b[n:], self.Balance)
	n += 2
	n += 2
	return
}
func (self SoundMediaInfo) Len() (n int) {
	n += 8
	n += 1
	n += 3
	n += 2
	n += 2
	return
}
func (self *SoundMediaInfo) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	if len(b) < n+1 {
		err = parseErr("Version", n+offset, err)
		return
	}
	self.Version = pio.U8(b[n:])
	n += 1
	if len(b) < n+3 {
		err = parseErr("Flags", n+offset, err)
		return
	}
	self.Flags = pio.U24BE(b[n:])
	n += 3
	if len(b) < n+2 {
		err = parseErr("Balance", n+offset, err)
		return
	}
	self.Balance = pio.I16BE(b[n:])
	n += 2
	n += 2
	return
}
func (self SoundMediaInfo) Children() (r []Atom) {
	return
}

type VideoMediaInfo struct {
	Version		uint8
	Flags		uint32
	GraphicsMode	int16
	Opcolor		[3]int16
	AtomPos
}

func (self VideoMediaInfo) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(VMHD))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self VideoMediaInfo) marshal(b []byte) (n int) {
	pio.PutU8(b[n:], self.Version)
	n += 1
	pio.PutU24BE(b[n:], self.Flags)
	n += 3
	pio.PutI16BE(b[n:], self.GraphicsMode)
	n += 2
	for _, entry := range self.Opcolor {
		pio.PutI16BE(b[n:], entry)
		n += 2
	}
	return
}
func (self VideoMediaInfo) Len() (n int) {
	n += 8
	n += 1
	n += 3
	n += 2
	n += 2*len(self.Opcolor[:])
	return
}
func (self *VideoMediaInfo) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	if len(b) < n+1 {
		err = parseErr("Version", n+offset, err)
		return
	}
	self.Version = pio.U8(b[n:])
	n += 1
	if len(b) < n+3 {
		err = parseErr("Flags", n+offset, err)
		return
	}
	self.Flags = pio.U24BE(b[n:])
	n += 3
	if len(b) < n+2 {
		err = parseErr("GraphicsMode", n+offset, err)
		return
	}
	self.GraphicsMode = pio.I16BE(b[n:])
	n += 2
	if len(b) < n+2*len(self.Opcolor) {
		err = parseErr("Opcolor", n+offset, err)
		return
	}
	for i := range self.Opcolor {
		self.Opcolor[i] = pio.I16BE(b[n:])
		n += 2
	}
	return
}
func (self VideoMediaInfo) Children() (r []Atom) {
	return
}

type SampleTable struct {
	SampleDesc		*SampleDesc
	TimeToSample		*TimeToSample
	CompositionOffset	*CompositionOffset
	SampleToChunk		*SampleToChunk
	SyncSample		*SyncSample
	ChunkOffset		*ChunkOffset
	SampleSize		*SampleSize
	AtomPos
}

func (self SampleTable) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(STBL))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self SampleTable) marshal(b []byte) (n int) {
	if self.SampleDesc != nil {
		n += self.SampleDesc.Marshal(b[n:])
	}
	if self.TimeToSample != nil {
		n += self.TimeToSample.Marshal(b[n:])
	}
	if self.CompositionOffset != nil {
		n += self.CompositionOffset.Marshal(b[n:])
	}
	if self.SampleToChunk != nil {
		n += self.SampleToChunk.Marshal(b[n:])
	}
	if self.SyncSample != nil {
		n += self.SyncSample.Marshal(b[n:])
	}
	if self.ChunkOffset != nil {
		n += self.ChunkOffset.Marshal(b[n:])
	}
	if self.SampleSize != nil {
		n += self.SampleSize.Marshal(b[n:])
	}
	return
}
func (self SampleTable) Len() (n int) {
	n += 8
	if self.SampleDesc != nil {
		n += self.SampleDesc.Len()
	}
	if self.TimeToSample != nil {
		n += self.TimeToSample.Len()
	}
	if self.CompositionOffset != nil {
		n += self.CompositionOffset.Len()
	}
	if self.SampleToChunk != nil {
		n += self.SampleToChunk.Len()
	}
	if self.SyncSample != nil {
		n += self.SyncSample.Len()
	}
	if self.ChunkOffset != nil {
		n += self.ChunkOffset.Len()
	}
	if self.SampleSize != nil {
		n += self.SampleSize.Len()
	}
	return
}
func (self *SampleTable) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	for n+8 < len(b) {
		tag := Tag(pio.U32BE(b[n+4:]))
		size := int(pio.U32BE(b[n:]))
		if len(b) < n+size {
			err = parseErr("TagSizeInvalid", n+offset, err)
			return
		}
		switch tag {
		case STSD:
			{
				atom := &SampleDesc{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("stsd", n+offset, err)
					return
				}
				self.SampleDesc = atom
			}
		case STTS:
			{
				atom := &TimeToSample{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("stts", n+offset, err)
					return
				}
				self.TimeToSample = atom
			}
		case CTTS:
			{
				atom := &CompositionOffset{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("ctts", n+offset, err)
					return
				}
				self.CompositionOffset = atom
			}
		case STSC:
			{
				atom := &SampleToChunk{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("stsc", n+offset, err)
					return
				}
				self.SampleToChunk = atom
			}
		case STSS:
			{
				atom := &SyncSample{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("stss", n+offset, err)
					return
				}
				self.SyncSample = atom
			}
		case STCO:
			{
				atom := &ChunkOffset{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("stco", n+offset, err)
					return
				}
				self.ChunkOffset = atom
			}
		case STSZ:
			{
				atom := &SampleSize{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("stsz", n+offset, err)
					return
				}
				self.SampleSize = atom
			}
		}
		n += size
	}
	return
}
func (self SampleTable) Children() (r []Atom) {
	if self.SampleDesc != nil {
		r = append(r, self.SampleDesc)
	}
	if self.TimeToSample != nil {
		r = append(r, self.TimeToSample)
	}
	if self.CompositionOffset != nil {
		r = append(r, self.CompositionOffset)
	}
	if self.SampleToChunk != nil {
		r = append(r, self.SampleToChunk)
	}
	if self.SyncSample != nil {
		r = append(r, self.SyncSample)
	}
	if self.ChunkOffset != nil {
		r = append(r, self.ChunkOffset)
	}
	if self.SampleSize != nil {
		r = append(r, self.SampleSize)
	}
	return
}

type SampleDesc struct {
	Version		uint8
	AVC1Desc	*AVC1Desc
	MP4ADesc	*MP4ADesc
	Unknowns	[]Atom
	AtomPos
}

func (self SampleDesc) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(STSD))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self SampleDesc) marshal(b []byte) (n int) {
	pio.PutU8(b[n:], self.Version)
	n += 1
	n += 3
	_childrenNR := 0
	if self.AVC1Desc != nil {
		_childrenNR++
	}
	if self.MP4ADesc != nil {
		_childrenNR++
	}
	_childrenNR += len(self.Unknowns)
	pio.PutI32BE(b[n:], int32(_childrenNR))
	n += 4
	if self.AVC1Desc != nil {
		n += self.AVC1Desc.Marshal(b[n:])
	}
	if self.MP4ADesc != nil {
		n += self.MP4ADesc.Marshal(b[n:])
	}
	for _, atom := range self.Unknowns {
		n += atom.Marshal(b[n:])
	}
	return
}
func (self SampleDesc) Len() (n int) {
	n += 8
	n += 1
	n += 3
	n += 4
	if self.AVC1Desc != nil {
		n += self.AVC1Desc.Len()
	}
	if self.MP4ADesc != nil {
		n += self.MP4ADesc.Len()
	}
	for _, atom := range self.Unknowns {
		n += atom.Len()
	}
	return
}
func (self *SampleDesc) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	if len(b) < n+1 {
		err = parseErr("Version", n+offset, err)
		return
	}
	self.Version = pio.U8(b[n:])
	n += 1
	n += 3
	n += 4
	for n+8 < len(b) {
		tag := Tag(pio.U32BE(b[n+4:]))
		size := int(pio.U32BE(b[n:]))
		if len(b) < n+size {
			err = parseErr("TagSizeInvalid", n+offset, err)
			return
		}
		switch tag {
		case AVC1:
			{
				atom := &AVC1Desc{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("avc1", n+offset, err)
					return
				}
				self.AVC1Desc = atom
			}
		case MP4A:
			{
				atom := &MP4ADesc{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("mp4a", n+offset, err)
					return
				}
				self.MP4ADesc = atom
			}
		default:
			{
				atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("", n+offset, err)
					return
				}
				self.Unknowns = append(self.Unknowns, atom)
			}
		}
		n += size
	}
	return
}
func (self SampleDesc) Children() (r []Atom) {
	if self.AVC1Desc != nil {
		r = append(r, self.AVC1Desc)
	}
	if self.MP4ADesc != nil {
		r = append(r, self.MP4ADesc)
	}
	r = append(r, self.Unknowns...)
	return
}

type MP4ADesc struct {
	DataRefIdx		int16
	Version			int16
	RevisionLevel		int16
	Vendor			int32
	NumberOfChannels	int16
	SampleSize		int16
	CompressionId		int16
	SampleRate		float64
	Conf			*ElemStreamDesc
	Unknowns		[]Atom
	AtomPos
}

func (self MP4ADesc) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(MP4A))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self MP4ADesc) marshal(b []byte) (n int) {
	n += 6
	pio.PutI16BE(b[n:], self.DataRefIdx)
	n += 2
	pio.PutI16BE(b[n:], self.Version)
	n += 2
	pio.PutI16BE(b[n:], self.RevisionLevel)
	n += 2
	pio.PutI32BE(b[n:], self.Vendor)
	n += 4
	pio.PutI16BE(b[n:], self.NumberOfChannels)
	n += 2
	pio.PutI16BE(b[n:], self.SampleSize)
	n += 2
	pio.PutI16BE(b[n:], self.CompressionId)
	n += 2
	n += 2
	PutFixed32(b[n:], self.SampleRate)
	n += 4
	if self.Conf != nil {
		n += self.Conf.Marshal(b[n:])
	}
	for _, atom := range self.Unknowns {
		n += atom.Marshal(b[n:])
	}
	return
}
func (self MP4ADesc) Len() (n int) {
	n += 8
	n += 6
	n += 2
	n += 2
	n += 2
	n += 4
	n += 2
	n += 2
	n += 2
	n += 2
	n += 4
	if self.Conf != nil {
		n += self.Conf.Len()
	}
	for _, atom := range self.Unknowns {
		n += atom.Len()
	}
	return
}
func (self *MP4ADesc) Unmarshal(b []byte, offset int) (n int, err error) {
	(&self.AtomPos).setPos(offset, len(b))
	n += 8
	n += 6
	if len(b) < n+2 {
		err = parseErr("DataRefIdx", n+offset, err)
		return
	}
	self.DataRefIdx = pio.I16BE(b[n:])
	n += 2
	if len(b) < n+2 {
		err = parseErr("Version", n+offset, err)
		return
	}
	self.Version = pio.I16BE(b[n:])
	n += 2
	if len(b) < n+2 {
		err = parseErr("RevisionLevel", n+offset, err)
		return
	}
	self.RevisionLevel = pio.I16BE(b[n:])
	n += 2
	if len(b) < n+4 {
		err = parseErr("Vendor", n+offset, err)
		return
	}
	self.Vendor = pio.I32BE(b[n:])
	n += 4
	if len(b) < n+2 {
		err = parseErr("NumberOfChannels", n+offset, err)
		return
	}
	self.NumberOfChannels = pio.I16BE(b[n:])
	n += 2
	if len(b) < n+2 {
		err = parseErr("SampleSize", n+offset, err)
		return
	}
	self.SampleSize = pio.I16BE(b[n:])
	n += 2
	if len(b) < n+2 {
		err = parseErr("CompressionId", n+offset, err)
		return
	}
	self.CompressionId = pio.I16BE(b[n:])
	n += 2
	n += 2
	if len(b) < n+4 {
		err = parseErr("SampleRate", n+offset, err)
		return
	}
	self.SampleRate = GetFixed32(b[n:])
	n += 4
	for n+8 < len(b) {
		tag := Tag(pio.U32BE(b[n+4:]))
		size := int(pio.U32BE(b[n:]))
		if len(b) < n+size {
			err = parseErr("TagSizeInvalid", n+offset, err)
			return
		}
		switch tag {
		case ESDS:
			{
				atom := &ElemStreamDesc{}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("esds", n+offset, err)
					return
				}
				self.Conf = atom
			}
		default:
			{
				atom := &Dummy{Tag_: tag, Data: b[n:n+size]}
				if _, err = atom.Unmarshal(b[n:n+size], offset+n); err != nil {
					err = parseErr("", n+offset, err)
					return
				}
				self.Unknowns = append(self.Unknowns, atom)
			}
		}
		n += size
	}
	return
}
func (self MP4ADesc) Children() (r []Atom) {
	if self.Conf != nil {
		r = append(r, self.Conf)
	}
	r = append(r, self.Unknowns...)
	return
}

type AVC1Desc struct {
	DataRefIdx		int16
	Version			int16
	Revision		int16
	Vendor			int32
	TemporalQuality		int32
	SpatialQuality		int32
	Width			int16
	Height			int16
	HorizontalResolution	float64
	VorizontalResolution	float64
	FrameCount		int16
	CompressorName		[32]byte
	Depth			int16
	ColorTableId		int16
	Conf			*AVC1Conf
	Unknowns		[]Atom
	AtomPos
}

func (self AVC1Desc) Marshal(b []byte) (n int) {
	pio.PutU32BE(b[4:], uint32(AVC1))
	n += self.marshal(b[8:])+8
	pio.PutU32BE(b[0:], uint32(n))
	return
}
func (self AVC1Desc) marshal(b []byte) (n int) {
	n += 6
	pio.PutI16BE(b[n:], self.DataRefIdx)
	n += 2
	pio.PutI16BE(b[n:], self.Version)
	n += 2
	pio.PutI16BE(b[n:], self.Revision)
	n += 2
	pio.PutI32BE(b[n:], self.Vendor)
	n += 4
	pio.PutI32BE(b[n:], self.TemporalQuality)
	n += 4
	pio.PutI32BE(b[n:], self.SpatialQuality)
	n += 4
	pio.PutI16BE(b[n:], self.Width)
	n += 2
	pio.PutI16BE(b[n:], self.Height)
	n += 2
	PutFixed32(b[n:], self.HorizontalResolution)
	n += 4
	PutFixed32(b[n:], self.VorizontalResolution)
	n += 4
	n += 4
	pio.PutI16BE(b[n:], self.FrameCount)
	n 
Download .txt
gitextract_naask5op/

├── LICENSE
├── README.md
├── av/
│   ├── av.go
│   ├── avconv/
│   │   └── avconv.go
│   ├── avutil/
│   │   └── avutil.go
│   ├── pktque/
│   │   ├── buf.go
│   │   ├── filters.go
│   │   └── timeline.go
│   ├── pubsub/
│   │   └── queue.go
│   └── transcode/
│       └── transcode.go
├── cgo/
│   └── ffmpeg/
│       ├── audio.go
│       ├── ffmpeg.go
│       ├── ffmpeg.h
│       └── video.go
├── codec/
│   ├── aacparser/
│   │   └── parser.go
│   ├── codec.go
│   ├── fake/
│   │   └── fake.go
│   └── h264parser/
│       ├── parser.go
│       └── parser_test.go
├── doc.go
├── examples/
│   ├── audio_decode/
│   │   └── main.go
│   ├── http_flv_and_rtmp_server/
│   │   └── main.go
│   ├── open_probe_file/
│   │   └── main.go
│   ├── rtmp_publish/
│   │   └── main.go
│   ├── rtmp_server_channels/
│   │   └── main.go
│   ├── rtmp_server_proxy/
│   │   └── main.go
│   ├── rtmp_server_speex_to_aac/
│   │   └── main.go
│   └── transcode/
│       └── main.go
├── format/
│   ├── aac/
│   │   └── aac.go
│   ├── flv/
│   │   ├── flv.go
│   │   └── flvio/
│   │       ├── amf0.go
│   │       └── flvio.go
│   ├── format.go
│   ├── mp4/
│   │   ├── demuxer.go
│   │   ├── handler.go
│   │   ├── mp4io/
│   │   │   ├── atoms.go
│   │   │   ├── gen/
│   │   │   │   ├── gen.go
│   │   │   │   └── pattern.go
│   │   │   └── mp4io.go
│   │   ├── muxer.go
│   │   └── stream.go
│   ├── rtmp/
│   │   └── rtmp.go
│   ├── rtsp/
│   │   ├── client.go
│   │   ├── conn.go
│   │   ├── sdp/
│   │   │   ├── parser.go
│   │   │   └── parser_test.go
│   │   └── stream.go
│   └── ts/
│       ├── demuxer.go
│       ├── handler.go
│       ├── muxer.go
│       ├── stream.go
│       └── tsio/
│           ├── checksum.go
│           └── tsio.go
└── utils/
    └── bits/
        ├── bits.go
        ├── bits_test.go
        ├── bufio/
        │   └── bufio.go
        ├── golomb_reader.go
        └── pio/
            ├── pio.go
            ├── reader.go
            ├── vec.go
            ├── vec_test.go
            └── writer.go
Download .txt
SYMBOL INDEX (1164 symbols across 58 files)

FILE: av/av.go
  type SampleFormat (line 11) | type SampleFormat
    method BytesPerSample (line 27) | func (self SampleFormat) BytesPerSample() int {
    method String (line 42) | func (self SampleFormat) String() string {
    method IsPlanar (line 70) | func (self SampleFormat) IsPlanar() bool {
  constant U8 (line 14) | U8 = SampleFormat(iota + 1)
  constant S16 (line 15) | S16
  constant S32 (line 16) | S32
  constant FLT (line 17) | FLT
  constant DBL (line 18) | DBL
  constant U8P (line 19) | U8P
  constant S16P (line 20) | S16P
  constant S32P (line 21) | S32P
  constant FLTP (line 22) | FLTP
  constant DBLP (line 23) | DBLP
  constant U32 (line 24) | U32
  type ChannelLayout (line 80) | type ChannelLayout
    method String (line 82) | func (self ChannelLayout) String() string {
    method Count (line 107) | func (self ChannelLayout) Count() (n int) {
  constant CH_FRONT_CENTER (line 87) | CH_FRONT_CENTER = ChannelLayout(1 << iota)
  constant CH_FRONT_LEFT (line 88) | CH_FRONT_LEFT
  constant CH_FRONT_RIGHT (line 89) | CH_FRONT_RIGHT
  constant CH_BACK_CENTER (line 90) | CH_BACK_CENTER
  constant CH_BACK_LEFT (line 91) | CH_BACK_LEFT
  constant CH_BACK_RIGHT (line 92) | CH_BACK_RIGHT
  constant CH_SIDE_LEFT (line 93) | CH_SIDE_LEFT
  constant CH_SIDE_RIGHT (line 94) | CH_SIDE_RIGHT
  constant CH_LOW_FREQ (line 95) | CH_LOW_FREQ
  constant CH_NR (line 96) | CH_NR
  constant CH_MONO (line 98) | CH_MONO     = ChannelLayout(CH_FRONT_CENTER)
  constant CH_STEREO (line 99) | CH_STEREO   = ChannelLayout(CH_FRONT_LEFT | CH_FRONT_RIGHT)
  constant CH_2_1 (line 100) | CH_2_1      = ChannelLayout(CH_STEREO | CH_BACK_CENTER)
  constant CH_2POINT1 (line 101) | CH_2POINT1  = ChannelLayout(CH_STEREO | CH_LOW_FREQ)
  constant CH_SURROUND (line 102) | CH_SURROUND = ChannelLayout(CH_STEREO | CH_FRONT_CENTER)
  constant CH_3POINT1 (line 103) | CH_3POINT1  = ChannelLayout(CH_SURROUND | CH_LOW_FREQ)
  type CodecType (line 116) | type CodecType
    method String (line 130) | func (self CodecType) String() string {
    method IsAudio (line 148) | func (self CodecType) IsAudio() bool {
    method IsVideo (line 152) | func (self CodecType) IsVideo() bool {
  constant codecTypeAudioBit (line 127) | codecTypeAudioBit = 0x1
  constant codecTypeOtherBits (line 128) | codecTypeOtherBits = 1
  function MakeAudioCodecType (line 157) | func MakeAudioCodecType(base uint32) (c CodecType) {
  function MakeVideoCodecType (line 163) | func MakeVideoCodecType(base uint32) (c CodecType) {
  constant avCodecTypeMagic (line 168) | avCodecTypeMagic = 233333
  type CodecData (line 176) | type CodecData interface
  type VideoCodecData (line 180) | type VideoCodecData interface
  type AudioCodecData (line 186) | type AudioCodecData interface
  type PacketWriter (line 194) | type PacketWriter interface
  type PacketReader (line 198) | type PacketReader interface
  type Muxer (line 205) | type Muxer interface
  type MuxCloser (line 212) | type MuxCloser interface
  type Demuxer (line 218) | type Demuxer interface
  type DemuxCloser (line 224) | type DemuxCloser interface
  type Packet (line 230) | type Packet struct
  type AudioFrame (line 239) | type AudioFrame struct
    method Duration (line 247) | func (self AudioFrame) Duration() time.Duration {
    method HasSameFormat (line 252) | func (self AudioFrame) HasSameFormat(other AudioFrame) bool {
    method Slice (line 266) | func (self AudioFrame) Slice(start int, end int) (out AudioFrame) {
    method Concat (line 281) | func (self AudioFrame) Concat(in AudioFrame) (out AudioFrame) {
  type AudioEncoder (line 293) | type AudioEncoder interface
  type AudioDecoder (line 307) | type AudioDecoder interface
  type AudioResampler (line 313) | type AudioResampler interface

FILE: av/avconv/avconv.go
  type Option (line 15) | type Option struct
  type Options (line 20) | type Options struct
  type Demuxer (line 24) | type Demuxer struct
    method Close (line 31) | func (self *Demuxer) Close() (err error) {
    method Streams (line 38) | func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
    method ReadPacket (line 46) | func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
    method prepare (line 53) | func (self *Demuxer) prepare() (err error) {
  function ConvertCmdline (line 121) | func ConvertCmdline(args []string) (err error) {

FILE: av/avutil/avutil.go
  type HandlerDemuxer (line 14) | type HandlerDemuxer struct
    method Close (line 19) | func (self *HandlerDemuxer) Close() error {
  type HandlerMuxer (line 23) | type HandlerMuxer struct
    method WriteHeader (line 29) | func (self *HandlerMuxer) WriteHeader(streams []av.CodecData) (err err...
    method WriteTrailer (line 39) | func (self *HandlerMuxer) WriteTrailer() (err error) {
    method Close (line 49) | func (self *HandlerMuxer) Close() (err error) {
  type RegisterHandler (line 56) | type RegisterHandler struct
  type Handlers (line 71) | type Handlers struct
    method Add (line 75) | func (self *Handlers) Add(fn func(*RegisterHandler)) {
    method openUrl (line 81) | func (self *Handlers) openUrl(u *url.URL, uri string) (r io.ReadCloser...
    method createUrl (line 98) | func (self *Handlers) createUrl(u *url.URL, uri string) (w io.WriteClo...
    method NewAudioEncoder (line 103) | func (self *Handlers) NewAudioEncoder(typ av.CodecType) (enc av.AudioE...
    method NewAudioDecoder (line 115) | func (self *Handlers) NewAudioDecoder(codec av.AudioCodecData) (dec av...
    method Open (line 127) | func (self *Handlers) Open(uri string) (demuxer av.DemuxCloser, err er...
    method Create (line 210) | func (self *Handlers) Create(uri string) (muxer av.MuxCloser, err erro...
    method FindCreate (line 215) | func (self *Handlers) FindCreate(uri string) (handler RegisterHandler,...
  function Open (line 270) | func Open(url string) (demuxer av.DemuxCloser, err error) {
  function Create (line 274) | func Create(url string) (muxer av.MuxCloser, err error) {
  function CopyPackets (line 278) | func CopyPackets(dst av.PacketWriter, src av.PacketReader) (err error) {
  function CopyFile (line 294) | func CopyFile(dst av.Muxer, src av.Demuxer) (err error) {

FILE: av/pktque/buf.go
  type Buf (line 7) | type Buf struct
    method Pop (line 20) | func (self *Buf) Pop() av.Packet {
    method grow (line 35) | func (self *Buf) grow() {
    method Push (line 43) | func (self *Buf) Push(pkt av.Packet) {
    method Get (line 53) | func (self *Buf) Get(pos BufPos) av.Packet {
    method IsValidPos (line 57) | func (self *Buf) IsValidPos(pos BufPos) bool {
  function NewBuf (line 14) | func NewBuf() *Buf {
  type BufPos (line 61) | type BufPos
    method LT (line 63) | func (self BufPos) LT(pos BufPos) bool {
    method GE (line 67) | func (self BufPos) GE(pos BufPos) bool {
    method GT (line 71) | func (self BufPos) GT(pos BufPos) bool {

FILE: av/pktque/filters.go
  type Filter (line 10) | type Filter interface
  type Filters (line 16) | type Filters
    method ModifyPacket (line 18) | func (self Filters) ModifyPacket(pkt *av.Packet, streams []av.CodecDat...
  type FilterDemuxer (line 31) | type FilterDemuxer struct
    method ReadPacket (line 39) | func (self FilterDemuxer) ReadPacket() (pkt av.Packet, err error) {
  type WaitKeyFrame (line 70) | type WaitKeyFrame struct
    method ModifyPacket (line 74) | func (self *WaitKeyFrame) ModifyPacket(pkt *av.Packet, streams []av.Co...
  type FixTime (line 83) | type FixTime struct
    method ModifyPacket (line 91) | func (self *FixTime) ModifyPacket(pkt *av.Packet, streams []av.CodecDa...
  type AVSync (line 115) | type AVSync struct
    method ModifyPacket (line 120) | func (self *AVSync) ModifyPacket(pkt *av.Packet, streams []av.CodecDat...
    method check (line 144) | func (self *AVSync) check(i int) (start time.Duration, end time.Durati...
  type Walltime (line 174) | type Walltime struct
    method ModifyPacket (line 178) | func (self *Walltime) ModifyPacket(pkt *av.Packet, streams []av.CodecD...

FILE: av/pktque/timeline.go
  type tlSeg (line 17) | type tlSeg struct
  type Timeline (line 21) | type Timeline struct
    method Push (line 26) | func (self *Timeline) Push(tm time.Duration, dur time.Duration) {
    method Pop (line 37) | func (self *Timeline) Pop(dur time.Duration) (tm time.Duration) {

FILE: av/pubsub/queue.go
  type Queue (line 23) | type Queue struct
    method SetMaxGopCount (line 44) | func (self *Queue) SetMaxGopCount(n int) {
    method WriteHeader (line 51) | func (self *Queue) WriteHeader(streams []av.CodecData) error {
    method WriteTrailer (line 67) | func (self *Queue) WriteTrailer() error {
    method Close (line 72) | func (self *Queue) Close() (err error) {
    method WritePacket (line 83) | func (self *Queue) WritePacket(pkt av.Packet) (err error) {
    method newCursor (line 115) | func (self *Queue) newCursor() *QueueCursor {
    method Latest (line 122) | func (self *Queue) Latest() *QueueCursor {
    method Oldest (line 131) | func (self *Queue) Oldest() *QueueCursor {
    method DelayedTime (line 140) | func (self *Queue) DelayedTime(dur time.Duration) *QueueCursor {
    method DelayedGopCount (line 159) | func (self *Queue) DelayedGopCount(n int) *QueueCursor {
  function NewQueue (line 34) | func NewQueue() *Queue {
  type QueueCursor (line 108) | type QueueCursor struct
    method Streams (line 176) | func (self *QueueCursor) Streams() (streams []av.CodecData, err error) {
    method ReadPacket (line 191) | func (self *QueueCursor) ReadPacket() (pkt av.Packet, err error) {

FILE: av/transcode/transcode.go
  type tStream (line 14) | type tStream struct
    method audioDecodeAndEncode (line 67) | func (self *tStream) audioDecodeAndEncode(inpkt av.Packet) (outpkts []...
  type Options (line 22) | type Options struct
  type Transcoder (line 29) | type Transcoder struct
    method Do (line 114) | func (self *Transcoder) Do(pkt av.Packet) (out []av.Packet, err error) {
    method Streams (line 127) | func (self *Transcoder) Streams() (streams []av.CodecData, err error) {
    method Close (line 135) | func (self *Transcoder) Close() (err error) {
  function NewTranscoder (line 33) | func NewTranscoder(streams []av.CodecData, options Options) (_self *Tran...
  type Muxer (line 152) | type Muxer struct
    method WriteHeader (line 158) | func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) {
    method WritePacket (line 172) | func (self *Muxer) WritePacket(pkt av.Packet) (err error) {
    method Close (line 185) | func (self *Muxer) Close() (err error) {
  type Demuxer (line 194) | type Demuxer struct
    method prepare (line 201) | func (self *Demuxer) prepare() (err error) {
    method ReadPacket (line 214) | func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
    method Streams (line 235) | func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
    method Close (line 242) | func (self *Demuxer) Close() (err error) {

FILE: cgo/ffmpeg/audio.go
  constant debug (line 24) | debug = false
  type Resampler (line 26) | type Resampler struct
    method Resample (line 33) | func (self *Resampler) Resample(in av.AudioFrame) (out av.AudioFrame, ...
    method Close (line 153) | func (self *Resampler) Close() {
  type AudioEncoder (line 157) | type AudioEncoder struct
    method SetSampleFormat (line 221) | func (self *AudioEncoder) SetSampleFormat(fmt av.SampleFormat) (err er...
    method SetSampleRate (line 226) | func (self *AudioEncoder) SetSampleRate(rate int) (err error) {
    method SetChannelLayout (line 231) | func (self *AudioEncoder) SetChannelLayout(ch av.ChannelLayout) (err e...
    method SetBitrate (line 236) | func (self *AudioEncoder) SetBitrate(bitrate int) (err error) {
    method SetOption (line 241) | func (self *AudioEncoder) SetOption(key string, val interface{}) (err ...
    method GetOption (line 258) | func (self *AudioEncoder) GetOption(key string, val interface{}) (err ...
    method Setup (line 277) | func (self *AudioEncoder) Setup() (err error) {
    method prepare (line 332) | func (self *AudioEncoder) prepare() (err error) {
    method CodecData (line 344) | func (self *AudioEncoder) CodecData() (codec av.AudioCodecData, err er...
    method encodeOne (line 352) | func (self *AudioEncoder) encodeOne(frame av.AudioFrame) (gotpkt bool,...
    method resample (line 390) | func (self *AudioEncoder) resample(in av.AudioFrame) (out av.AudioFram...
    method Encode (line 404) | func (self *AudioEncoder) Encode(frame av.AudioFrame) (pkts [][]byte, ...
    method Close (line 442) | func (self *AudioEncoder) Close() {
  function sampleFormatAV2FF (line 169) | func sampleFormatAV2FF(sampleFormat av.SampleFormat) (ffsamplefmt int32) {
  function sampleFormatFF2AV (line 195) | func sampleFormatFF2AV(ffsamplefmt int32) (sampleFormat av.SampleFormat) {
  function audioFrameAssignToAVParams (line 450) | func audioFrameAssignToAVParams(f *C.AVFrame, frame *av.AudioFrame) {
  function audioFrameAssignToAVData (line 456) | func audioFrameAssignToAVData(f *C.AVFrame, frame *av.AudioFrame) {
  function audioFrameAssignToAV (line 464) | func audioFrameAssignToAV(f *C.AVFrame, frame *av.AudioFrame) {
  function audioFrameAssignToFFParams (line 469) | func audioFrameAssignToFFParams(frame av.AudioFrame, f *C.AVFrame) {
  function audioFrameAssignToFFData (line 476) | func audioFrameAssignToFFData(frame av.AudioFrame, f *C.AVFrame) {
  function audioFrameAssignToFF (line 484) | func audioFrameAssignToFF(frame av.AudioFrame, f *C.AVFrame) {
  function channelLayoutFF2AV (line 489) | func channelLayoutFF2AV(layout C.uint64_t) (channelLayout av.ChannelLayo...
  function channelLayoutAV2FF (line 520) | func channelLayoutAV2FF(channelLayout av.ChannelLayout) (layout C.uint64...
  type AudioDecoder (line 551) | type AudioDecoder struct
    method Setup (line 559) | func (self *AudioDecoder) Setup() (err error) {
    method Decode (line 588) | func (self *AudioDecoder) Decode(pkt []byte) (gotframe bool, frame av....
    method Close (line 611) | func (self *AudioDecoder) Close() {
  function NewAudioEncoderByCodecType (line 615) | func NewAudioEncoderByCodecType(typ av.CodecType) (enc *AudioEncoder, er...
  function NewAudioEncoderByName (line 641) | func NewAudioEncoderByName(name string) (enc *AudioEncoder, err error) {
  function NewAudioDecoder (line 657) | func NewAudioDecoder(codec av.AudioCodecData) (dec *AudioDecoder, err er...
  type audioCodecData (line 711) | type audioCodecData struct
    method Type (line 719) | func (self audioCodecData) Type() av.CodecType {
    method SampleRate (line 723) | func (self audioCodecData) SampleRate() int {
    method SampleFormat (line 727) | func (self audioCodecData) SampleFormat() av.SampleFormat {
    method ChannelLayout (line 731) | func (self audioCodecData) ChannelLayout() av.ChannelLayout {
    method PacketDuration (line 735) | func (self audioCodecData) PacketDuration(data []byte) (dur time.Durat...
  function AudioCodecHandler (line 741) | func AudioCodecHandler(h *avutil.RegisterHandler) {

FILE: cgo/ffmpeg/ffmpeg.go
  constant QUIET (line 17) | QUIET = int(C.AV_LOG_QUIET)
  constant PANIC (line 18) | PANIC = int(C.AV_LOG_PANIC)
  constant FATAL (line 19) | FATAL = int(C.AV_LOG_FATAL)
  constant ERROR (line 20) | ERROR = int(C.AV_LOG_ERROR)
  constant WARNING (line 21) | WARNING = int(C.AV_LOG_WARNING)
  constant INFO (line 22) | INFO = int(C.AV_LOG_INFO)
  constant VERBOSE (line 23) | VERBOSE = int(C.AV_LOG_VERBOSE)
  constant DEBUG (line 24) | DEBUG = int(C.AV_LOG_DEBUG)
  constant TRACE (line 25) | TRACE = int(C.AV_LOG_TRACE)
  function HasEncoder (line 28) | func HasEncoder(name string) bool {
  function HasDecoder (line 32) | func HasDecoder(name string) bool {
  function SetLogLevel (line 39) | func SetLogLevel(level int) {
  function init (line 43) | func init() {
  type ffctx (line 47) | type ffctx struct
  function newFFCtxByCodec (line 51) | func newFFCtxByCodec(codec *C.AVCodec) (ff *ffctx, err error) {
  function freeFFCtx (line 60) | func freeFFCtx(self *ffctx) {

FILE: cgo/ffmpeg/ffmpeg.h
  type FFCtx (line 10) | typedef struct {
  function avcodec_profile_name_to_int (line 18) | static inline int avcodec_profile_name_to_int(AVCodec *codec, const char...

FILE: cgo/ffmpeg/video.go
  type VideoDecoder (line 21) | type VideoDecoder struct
    method Setup (line 26) | func (self *VideoDecoder) Setup() (err error) {
    method Decode (line 61) | func (self *VideoDecoder) Decode(pkt []byte) (img *VideoFrame, err err...
  function fromCPtr (line 39) | func fromCPtr(buf unsafe.Pointer, size int) (ret []uint8) {
  type VideoFrame (line 47) | type VideoFrame struct
    method Free (line 52) | func (self *VideoFrame) Free() {
  function freeVideoFrame (line 57) | func freeVideoFrame(self *VideoFrame) {
  function NewVideoDecoder (line 93) | func NewVideoDecoder(stream av.CodecData) (dec *VideoDecoder, err error) {

FILE: codec/aacparser/parser.go
  constant AOT_AAC_MAIN (line 14) | AOT_AAC_MAIN        = 1 + iota
  constant AOT_AAC_LC (line 15) | AOT_AAC_LC
  constant AOT_AAC_SSR (line 16) | AOT_AAC_SSR
  constant AOT_AAC_LTP (line 17) | AOT_AAC_LTP
  constant AOT_SBR (line 18) | AOT_SBR
  constant AOT_AAC_SCALABLE (line 19) | AOT_AAC_SCALABLE
  constant AOT_TWINVQ (line 20) | AOT_TWINVQ
  constant AOT_CELP (line 21) | AOT_CELP
  constant AOT_HVXC (line 22) | AOT_HVXC
  constant AOT_TTSI (line 23) | AOT_TTSI            = 12 + iota
  constant AOT_MAINSYNTH (line 24) | AOT_MAINSYNTH
  constant AOT_WAVESYNTH (line 25) | AOT_WAVESYNTH
  constant AOT_MIDI (line 26) | AOT_MIDI
  constant AOT_SAFX (line 27) | AOT_SAFX
  constant AOT_ER_AAC_LC (line 28) | AOT_ER_AAC_LC
  constant AOT_ER_AAC_LTP (line 29) | AOT_ER_AAC_LTP      = 19 + iota
  constant AOT_ER_AAC_SCALABLE (line 30) | AOT_ER_AAC_SCALABLE
  constant AOT_ER_TWINVQ (line 31) | AOT_ER_TWINVQ
  constant AOT_ER_BSAC (line 32) | AOT_ER_BSAC
  constant AOT_ER_AAC_LD (line 33) | AOT_ER_AAC_LD
  constant AOT_ER_CELP (line 34) | AOT_ER_CELP
  constant AOT_ER_HVXC (line 35) | AOT_ER_HVXC
  constant AOT_ER_HILN (line 36) | AOT_ER_HILN
  constant AOT_ER_PARAM (line 37) | AOT_ER_PARAM
  constant AOT_SSC (line 38) | AOT_SSC
  constant AOT_PS (line 39) | AOT_PS
  constant AOT_SURROUND (line 40) | AOT_SURROUND
  constant AOT_ESCAPE (line 41) | AOT_ESCAPE
  constant AOT_L1 (line 42) | AOT_L1
  constant AOT_L2 (line 43) | AOT_L2
  constant AOT_L3 (line 44) | AOT_L3
  constant AOT_DST (line 45) | AOT_DST
  constant AOT_ALS (line 46) | AOT_ALS
  constant AOT_SLS (line 47) | AOT_SLS
  constant AOT_SLS_NON_CORE (line 48) | AOT_SLS_NON_CORE
  constant AOT_ER_AAC_ELD (line 49) | AOT_ER_AAC_ELD
  constant AOT_SMR_SIMPLE (line 50) | AOT_SMR_SIMPLE
  constant AOT_SMR_MAIN (line 51) | AOT_SMR_MAIN
  constant AOT_USAC_NOSBR (line 52) | AOT_USAC_NOSBR
  constant AOT_SAOC (line 53) | AOT_SAOC
  constant AOT_LD_SURROUND (line 54) | AOT_LD_SURROUND
  constant AOT_USAC (line 55) | AOT_USAC
  type MPEG4AudioConfig (line 58) | type MPEG4AudioConfig struct
    method IsValid (line 202) | func (self MPEG4AudioConfig) IsValid() bool {
    method Complete (line 206) | func (self *MPEG4AudioConfig) Complete() {
  function ParseADTSHeader (line 94) | func ParseADTSHeader(frame []byte) (config MPEG4AudioConfig, hdrlen int,...
  constant ADTSHeaderLength (line 120) | ADTSHeaderLength = 7
  function FillADTSHeader (line 122) | func FillADTSHeader(header []byte, config MPEG4AudioConfig, samples int,...
  function readObjectType (line 144) | func readObjectType(r *bits.Reader) (objectType uint, err error) {
  function writeObjectType (line 158) | func writeObjectType(w *bits.Writer, objectType uint) (err error) {
  function readSampleRateIndex (line 174) | func readSampleRateIndex(r *bits.Reader) (index uint, err error) {
  function writeSampleRateIndex (line 186) | func writeSampleRateIndex(w *bits.Writer, index uint) (err error) {
  function ParseMPEG4AudioConfigBytes (line 216) | func ParseMPEG4AudioConfigBytes(data []byte) (config MPEG4AudioConfig, e...
  function WriteMPEG4AudioConfig (line 233) | func WriteMPEG4AudioConfig(w io.Writer, config MPEG4AudioConfig) (err er...
  type CodecData (line 267) | type CodecData struct
    method Type (line 272) | func (self CodecData) Type() av.CodecType {
    method MPEG4AudioConfigBytes (line 276) | func (self CodecData) MPEG4AudioConfigBytes() []byte {
    method ChannelLayout (line 280) | func (self CodecData) ChannelLayout() av.ChannelLayout {
    method SampleRate (line 284) | func (self CodecData) SampleRate() int {
    method SampleFormat (line 288) | func (self CodecData) SampleFormat() av.SampleFormat {
    method PacketDuration (line 292) | func (self CodecData) PacketDuration(data []byte) (dur time.Duration, ...
  function NewCodecDataFromMPEG4AudioConfig (line 297) | func NewCodecDataFromMPEG4AudioConfig(config MPEG4AudioConfig) (self Cod...
  function NewCodecDataFromMPEG4AudioConfigBytes (line 303) | func NewCodecDataFromMPEG4AudioConfigBytes(config []byte) (self CodecDat...

FILE: codec/codec.go
  type PCMUCodecData (line 9) | type PCMUCodecData struct
    method Type (line 13) | func (self PCMUCodecData) Type() av.CodecType {
    method SampleRate (line 17) | func (self PCMUCodecData) SampleRate() int {
    method ChannelLayout (line 21) | func (self PCMUCodecData) ChannelLayout() av.ChannelLayout {
    method SampleFormat (line 25) | func (self PCMUCodecData) SampleFormat() av.SampleFormat {
    method PacketDuration (line 29) | func (self PCMUCodecData) PacketDuration(data []byte) (time.Duration, ...
  function NewPCMMulawCodecData (line 33) | func NewPCMMulawCodecData() av.AudioCodecData {
  function NewPCMAlawCodecData (line 39) | func NewPCMAlawCodecData() av.AudioCodecData {
  type SpeexCodecData (line 45) | type SpeexCodecData struct
    method PacketDuration (line 49) | func (self SpeexCodecData) PacketDuration(data []byte) (time.Duration,...
  function NewSpeexCodecData (line 56) | func NewSpeexCodecData(sr int, cl av.ChannelLayout) SpeexCodecData {

FILE: codec/fake/fake.go
  type CodecData (line 7) | type CodecData struct
    method Type (line 14) | func (self CodecData) Type() av.CodecType {
    method SampleFormat (line 18) | func (self CodecData) SampleFormat() av.SampleFormat {
    method ChannelLayout (line 22) | func (self CodecData) ChannelLayout() av.ChannelLayout {
    method SampleRate (line 26) | func (self CodecData) SampleRate() int {

FILE: codec/h264parser/parser.go
  constant NALU_SEI (line 13) | NALU_SEI = 6
  constant NALU_PPS (line 14) | NALU_PPS = 7
  constant NALU_SPS (line 15) | NALU_SPS = 8
  constant NALU_AUD (line 16) | NALU_AUD = 9
  function IsDataNALU (line 19) | func IsDataNALU(b []byte) bool {
  function CheckNALUsType (line 205) | func CheckNALUsType(b []byte) (typ int) {
  constant NALU_RAW (line 211) | NALU_RAW = iota
  constant NALU_AVCC (line 212) | NALU_AVCC
  constant NALU_ANNEXB (line 213) | NALU_ANNEXB
  function SplitNALUs (line 216) | func SplitNALUs(b []byte) (nalus [][]byte, typ int) {
  type SPSInfo (line 293) | type SPSInfo struct
  function ParseSPS (line 309) | func ParseSPS(data []byte) (self SPSInfo, err error) {
  type CodecData (line 501) | type CodecData struct
    method Type (line 507) | func (self CodecData) Type() av.CodecType {
    method AVCDecoderConfRecordBytes (line 511) | func (self CodecData) AVCDecoderConfRecordBytes() []byte {
    method SPS (line 515) | func (self CodecData) SPS() []byte {
    method PPS (line 519) | func (self CodecData) PPS() []byte {
    method Width (line 523) | func (self CodecData) Width() int {
    method Height (line 527) | func (self CodecData) Height() int {
  function NewCodecDataFromAVCDecoderConfRecord (line 531) | func NewCodecDataFromAVCDecoderConfRecord(record []byte) (self CodecData...
  function NewCodecDataFromSPSAndPPS (line 551) | func NewCodecDataFromSPSAndPPS(sps, pps []byte) (self CodecData, err err...
  type AVCDecoderConfRecord (line 572) | type AVCDecoderConfRecord struct
    method Unmarshal (line 583) | func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err erro...
    method Len (line 638) | func (self AVCDecoderConfRecord) Len() (n int) {
    method Marshal (line 649) | func (self AVCDecoderConfRecord) Marshal(b []byte) (n int) {
  type SliceType (line 678) | type SliceType
    method String (line 680) | func (self SliceType) String() string {
  constant SLICE_P (line 693) | SLICE_P = iota+1
  constant SLICE_B (line 694) | SLICE_B
  constant SLICE_I (line 695) | SLICE_I
  function ParseSliceHeaderFromNALU (line 698) | func ParseSliceHeaderFromNALU(packet []byte) (sliceType SliceType, err e...

FILE: codec/h264parser/parser_test.go
  function TestParser (line 9) | func TestParser(t *testing.T) {

FILE: examples/audio_decode/main.go
  function init (line 13) | func init() {
  function main (line 17) | func main() {

FILE: examples/http_flv_and_rtmp_server/main.go
  function init (line 14) | func init() {
  type writeFlusher (line 18) | type writeFlusher struct
    method Flush (line 23) | func (self writeFlusher) Flush() error {
  function main (line 28) | func main() {

FILE: examples/open_probe_file/main.go
  function init (line 10) | func init() {
  function main (line 14) | func main() {

FILE: examples/rtmp_publish/main.go
  function init (line 10) | func init() {
  function main (line 16) | func main() {

FILE: examples/rtmp_server_channels/main.go
  function init (line 15) | func init() {
  type FrameDropper (line 19) | type FrameDropper struct
    method ModifyPacket (line 30) | func (self *FrameDropper) ModifyPacket(pkt *av.Packet, streams []av.Co...
  function main (line 75) | func main() {

FILE: examples/rtmp_server_proxy/main.go
  function init (line 11) | func init() {
  function main (line 15) | func main() {

FILE: examples/rtmp_server_speex_to_aac/main.go
  function init (line 18) | func init() {
  function main (line 22) | func main() {

FILE: examples/transcode/main.go
  function init (line 13) | func init() {
  function main (line 17) | func main() {

FILE: format/aac/aac.go
  type Muxer (line 14) | type Muxer struct
    method WriteHeader (line 27) | func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) {
    method WritePacket (line 39) | func (self *Muxer) WritePacket(pkt av.Packet) (err error) {
    method WriteTrailer (line 50) | func (self *Muxer) WriteTrailer() (err error) {
  function NewMuxer (line 20) | func NewMuxer(w io.Writer) *Muxer {
  type Demuxer (line 54) | type Demuxer struct
    method Streams (line 67) | func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
    method ReadPacket (line 85) | func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
  function NewDemuxer (line 61) | func NewDemuxer(r io.Reader) *Demuxer {
  function Handler (line 107) | func Handler(h *avutil.RegisterHandler) {

FILE: format/flv/flv.go
  function NewMetadataByStreams (line 19) | func NewMetadataByStreams(streams []av.CodecData) (metadata flvio.AMFMap...
  type Prober (line 62) | type Prober struct
    method CacheTag (line 71) | func (self *Prober) CacheTag(_tag flvio.Tag, timestamp int32) {
    method PushTag (line 76) | func (self *Prober) PushTag(tag flvio.Tag, timestamp int32) (err error) {
    method Probed (line 152) | func (self *Prober) Probed() (ok bool) {
    method TagToPacket (line 165) | func (self *Prober) TagToPacket(tag flvio.Tag, timestamp int32) (pkt a...
    method Empty (line 201) | func (self *Prober) Empty() bool {
    method PopPacket (line 205) | func (self *Prober) PopPacket() av.Packet {
  function CodecDataToTag (line 211) | func CodecDataToTag(stream av.CodecData) (_tag flvio.Tag, ok bool, err e...
  function PacketToTag (line 259) | func PacketToTag(pkt av.Packet, stream av.CodecData) (tag flvio.Tag, tim...
  type Muxer (line 316) | type Muxer struct
    method WriteHeader (line 340) | func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) {
    method WritePacket (line 372) | func (self *Muxer) WritePacket(pkt av.Packet) (err error) {
    method WriteTrailer (line 382) | func (self *Muxer) WriteTrailer() (err error) {
  type writeFlusher (line 322) | type writeFlusher interface
  function NewMuxerWriteFlusher (line 327) | func NewMuxerWriteFlusher(w writeFlusher) *Muxer {
  function NewMuxer (line 334) | func NewMuxer(w io.Writer) *Muxer {
  type Demuxer (line 389) | type Demuxer struct
    method prepare (line 404) | func (self *Demuxer) prepare() (err error) {
    method Streams (line 444) | func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
    method ReadPacket (line 452) | func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
  function NewDemuxer (line 396) | func NewDemuxer(r io.Reader) *Demuxer {
  function Handler (line 478) | func Handler(h *avutil.RegisterHandler) {

FILE: format/flv/flvio/amf0.go
  type AMF0ParseError (line 11) | type AMF0ParseError struct
    method Error (line 17) | func (self *AMF0ParseError) Error() string {
  function amf0ParseErr (line 25) | func amf0ParseErr(message string, offset int, err error) error {
  type AMFMap (line 34) | type AMFMap
  type AMFArray (line 35) | type AMFArray
  type AMFECMAArray (line 36) | type AMFECMAArray
  function parseBEFloat64 (line 38) | func parseBEFloat64(b []byte) float64 {
  function fillBEFloat64 (line 42) | func fillBEFloat64(b []byte, f float64) int {
  constant lenAMF0Number (line 47) | lenAMF0Number = 9
  function fillAMF0Number (line 49) | func fillAMF0Number(b []byte, f float64) int {
  constant amf3undefinedmarker (line 56) | amf3undefinedmarker = iota
  constant amf3nullmarker (line 57) | amf3nullmarker
  constant amf3falsemarker (line 58) | amf3falsemarker
  constant amf3truemarker (line 59) | amf3truemarker
  constant amf3integermarker (line 60) | amf3integermarker
  constant amf3doublemarker (line 61) | amf3doublemarker
  constant amf3stringmarker (line 62) | amf3stringmarker
  constant amf3xmldocmarker (line 63) | amf3xmldocmarker
  constant amf3datemarker (line 64) | amf3datemarker
  constant amf3arraymarker (line 65) | amf3arraymarker
  constant amf3objectmarker (line 66) | amf3objectmarker
  constant amf3xmlmarker (line 67) | amf3xmlmarker
  constant amf3bytearraymarker (line 68) | amf3bytearraymarker
  constant amf3vectorintmarker (line 69) | amf3vectorintmarker
  constant amf3vectoruintmarker (line 70) | amf3vectoruintmarker
  constant amf3vectordoublemarker (line 71) | amf3vectordoublemarker
  constant amf3vectorobjectmarker (line 72) | amf3vectorobjectmarker
  constant amf3dictionarymarker (line 73) | amf3dictionarymarker
  constant numbermarker (line 77) | numbermarker = iota
  constant booleanmarker (line 78) | booleanmarker
  constant stringmarker (line 79) | stringmarker
  constant objectmarker (line 80) | objectmarker
  constant movieclipmarker (line 81) | movieclipmarker
  constant nullmarker (line 82) | nullmarker
  constant undefinedmarker (line 83) | undefinedmarker
  constant referencemarker (line 84) | referencemarker
  constant ecmaarraymarker (line 85) | ecmaarraymarker
  constant objectendmarker (line 86) | objectendmarker
  constant strictarraymarker (line 87) | strictarraymarker
  constant datemarker (line 88) | datemarker
  constant longstringmarker (line 89) | longstringmarker
  constant unsupportedmarker (line 90) | unsupportedmarker
  constant recordsetmarker (line 91) | recordsetmarker
  constant xmldocumentmarker (line 92) | xmldocumentmarker
  constant typedobjectmarker (line 93) | typedobjectmarker
  constant avmplusobjectmarker (line 94) | avmplusobjectmarker
  function LenAMF0Val (line 97) | func LenAMF0Val(_val interface{}) (n int) {
  function FillAMF0Val (line 170) | func FillAMF0Val(b []byte, _val interface{}) (n int) {
  function ParseAMF0Val (line 282) | func ParseAMF0Val(b []byte) (val interface{}, n int, err error) {
  function parseAMF0Val (line 286) | func parseAMF0Val(b []byte, offset int) (val interface{}, n int, err err...

FILE: format/flv/flvio/flvio.go
  function TsToTime (line 11) | func TsToTime(ts int32) time.Duration {
  function TimeToTs (line 15) | func TimeToTs(tm time.Duration) int32 {
  constant MaxTagSubHeaderLength (line 19) | MaxTagSubHeaderLength = 16
  constant TAG_AUDIO (line 22) | TAG_AUDIO      = 8
  constant TAG_VIDEO (line 23) | TAG_VIDEO      = 9
  constant TAG_SCRIPTDATA (line 24) | TAG_SCRIPTDATA = 18
  constant SOUND_MP3 (line 28) | SOUND_MP3                   = 2
  constant SOUND_NELLYMOSER_16KHZ_MONO (line 29) | SOUND_NELLYMOSER_16KHZ_MONO = 4
  constant SOUND_NELLYMOSER_8KHZ_MONO (line 30) | SOUND_NELLYMOSER_8KHZ_MONO  = 5
  constant SOUND_NELLYMOSER (line 31) | SOUND_NELLYMOSER            = 6
  constant SOUND_ALAW (line 32) | SOUND_ALAW                  = 7
  constant SOUND_MULAW (line 33) | SOUND_MULAW                 = 8
  constant SOUND_AAC (line 34) | SOUND_AAC                   = 10
  constant SOUND_SPEEX (line 35) | SOUND_SPEEX                 = 11
  constant SOUND_5_5Khz (line 37) | SOUND_5_5Khz = 0
  constant SOUND_11Khz (line 38) | SOUND_11Khz  = 1
  constant SOUND_22Khz (line 39) | SOUND_22Khz  = 2
  constant SOUND_44Khz (line 40) | SOUND_44Khz  = 3
  constant SOUND_8BIT (line 42) | SOUND_8BIT  = 0
  constant SOUND_16BIT (line 43) | SOUND_16BIT = 1
  constant SOUND_MONO (line 45) | SOUND_MONO   = 0
  constant SOUND_STEREO (line 46) | SOUND_STEREO = 1
  constant AAC_SEQHDR (line 48) | AAC_SEQHDR = 0
  constant AAC_RAW (line 49) | AAC_RAW    = 1
  constant AVC_SEQHDR (line 53) | AVC_SEQHDR = 0
  constant AVC_NALU (line 54) | AVC_NALU   = 1
  constant AVC_EOS (line 55) | AVC_EOS    = 2
  constant FRAME_KEY (line 57) | FRAME_KEY   = 1
  constant FRAME_INTER (line 58) | FRAME_INTER = 2
  constant VIDEO_H264 (line 60) | VIDEO_H264 = 7
  type Tag (line 63) | type Tag struct
    method ChannelLayout (line 155) | func (self Tag) ChannelLayout() av.ChannelLayout {
    method audioParseHeader (line 163) | func (self *Tag) audioParseHeader(b []byte) (n int, err error) {
    method audioFillHeader (line 189) | func (self Tag) audioFillHeader(b []byte) (n int) {
    method videoParseHeader (line 207) | func (self *Tag) videoParseHeader(b []byte) (n int, err error) {
    method videoFillHeader (line 232) | func (self Tag) videoFillHeader(b []byte) (n int) {
    method FillHeader (line 243) | func (self Tag) FillHeader(b []byte) (n int) {
    method ParseHeader (line 255) | func (self *Tag) ParseHeader(b []byte) (n int, err error) {
  constant FILE_HAS_AUDIO (line 272) | FILE_HAS_AUDIO = 0x4
  constant FILE_HAS_VIDEO (line 273) | FILE_HAS_VIDEO = 0x1
  constant TagHeaderLength (line 276) | TagHeaderLength = 11
  constant TagTrailerLength (line 277) | TagTrailerLength = 4
  function ParseTagHeader (line 279) | func ParseTagHeader(b []byte) (tag Tag, ts int32, datalen int, err error) {
  function ReadTag (line 302) | func ReadTag(r io.Reader, b []byte) (tag Tag, ts int32, err error) {
  function FillTagHeader (line 328) | func FillTagHeader(b []byte, tagtype uint8, datalen int, ts int32) (n in...
  function FillTagTrailer (line 342) | func FillTagTrailer(b []byte, datalen int) (n int) {
  function WriteTag (line 348) | func WriteTag(w io.Writer, tag Tag, ts int32, b []byte) (err error) {
  constant FileHeaderLength (line 372) | FileHeaderLength = 9
  function FillFileHeader (line 374) | func FillFileHeader(b []byte, flags uint8) (n int) {
  function ParseFileHeader (line 394) | func ParseFileHeader(b []byte) (flags uint8, skip int, err error) {

FILE: format/format.go
  function RegisterAll (line 13) | func RegisterAll() {

FILE: format/mp4/demuxer.go
  type Demuxer (line 15) | type Demuxer struct
    method Streams (line 27) | func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
    method readat (line 37) | func (self *Demuxer) readat(pos int64, b []byte) (err error) {
    method probe (line 47) | func (self *Demuxer) probe() (err error) {
    method ReadPacket (line 300) | func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
    method CurrentTime (line 329) | func (self *Demuxer) CurrentTime() (tm time.Duration) {
    method SeekToTime (line 337) | func (self *Demuxer) SeekToTime(tm time.Duration) (err error) {
  function NewDemuxer (line 21) | func NewDemuxer(r io.ReadSeeker) *Demuxer {
  method setSampleIndex (line 105) | func (self *Stream) setSampleIndex(index int) (err error) {
  method isSampleValid (line 202) | func (self *Stream) isSampleValid() bool {
  method incSampleIndex (line 230) | func (self *Stream) incSampleIndex() (duration int64) {
  method sampleCount (line 282) | func (self *Stream) sampleCount() int {
  method readPacket (line 359) | func (self *Stream) readPacket() (pkt av.Packet, err error) {
  method seekToTime (line 397) | func (self *Stream) seekToTime(tm time.Duration) (err error) {
  method timeToSampleIndex (line 408) | func (self *Stream) timeToSampleIndex(tm time.Duration) int {

FILE: format/mp4/handler.go
  function Handler (line 11) | func Handler(h *avutil.RegisterHandler) {

FILE: format/mp4/mp4io/atoms.go
  constant MOOF (line 6) | MOOF = Tag(0x6d6f6f66)
  constant HDLR (line 12) | HDLR = Tag(0x68646c72)
  constant AVC1 (line 18) | AVC1 = Tag(0x61766331)
  constant URL (line 24) | URL  = Tag(0x75726c20)
  constant TREX (line 30) | TREX = Tag(0x74726578)
  constant ESDS (line 36) | ESDS = Tag(0x65736473)
  method Tag (line 38) | func (self ElemStreamDesc) Tag() Tag {
  constant MDHD (line 42) | MDHD = Tag(0x6d646864)
  constant STTS (line 48) | STTS = Tag(0x73747473)
  constant STSS (line 54) | STSS = Tag(0x73747373)
  constant MFHD (line 60) | MFHD = Tag(0x6d666864)
  constant MVHD (line 66) | MVHD = Tag(0x6d766864)
  constant MINF (line 72) | MINF = Tag(0x6d696e66)
  constant MOOV (line 78) | MOOV = Tag(0x6d6f6f76)
  constant MVEX (line 84) | MVEX = Tag(0x6d766578)
  constant STSD (line 90) | STSD = Tag(0x73747364)
  constant MP4A (line 96) | MP4A = Tag(0x6d703461)
  constant CTTS (line 102) | CTTS = Tag(0x63747473)
  constant STCO (line 108) | STCO = Tag(0x7374636f)
  constant TRUN (line 114) | TRUN = Tag(0x7472756e)
  constant TRAK (line 120) | TRAK = Tag(0x7472616b)
  constant MDIA (line 126) | MDIA = Tag(0x6d646961)
  constant STSC (line 132) | STSC = Tag(0x73747363)
  constant VMHD (line 138) | VMHD = Tag(0x766d6864)
  constant STBL (line 144) | STBL = Tag(0x7374626c)
  constant AVCC (line 150) | AVCC = Tag(0x61766343)
  constant TFDT (line 156) | TFDT = Tag(0x74666474)
  constant DINF (line 162) | DINF = Tag(0x64696e66)
  constant DREF (line 168) | DREF = Tag(0x64726566)
  constant TRAF (line 174) | TRAF = Tag(0x74726166)
  constant STSZ (line 180) | STSZ = Tag(0x7374737a)
  constant TFHD (line 186) | TFHD = Tag(0x74666864)
  constant TKHD (line 192) | TKHD = Tag(0x746b6864)
  constant SMHD (line 198) | SMHD = Tag(0x736d6864)
  constant MDAT (line 204) | MDAT = Tag(0x6d646174)
  type Movie (line 206) | type Movie struct
    method Tag (line 80) | func (self Movie) Tag() Tag {
    method Marshal (line 214) | func (self Movie) Marshal(b []byte) (n int) {
    method marshal (line 220) | func (self Movie) marshal(b []byte) (n int) {
    method Len (line 235) | func (self Movie) Len() (n int) {
    method Unmarshal (line 251) | func (self *Movie) Unmarshal(b []byte, offset int) (n int, err error) {
    method Children (line 303) | func (self Movie) Children() (r []Atom) {
  type MovieHeader (line 317) | type MovieHeader struct
    method Tag (line 68) | func (self MovieHeader) Tag() Tag {
    method Marshal (line 337) | func (self MovieHeader) Marshal(b []byte) (n int) {
    method marshal (line 343) | func (self MovieHeader) marshal(b []byte) (n int) {
    method Len (line 381) | func (self MovieHeader) Len() (n int) {
    method Unmarshal (line 402) | func (self *MovieHeader) Unmarshal(b []byte, offset int) (n int, err e...
    method Children (line 506) | func (self MovieHeader) Children() (r []Atom) {
  type Track (line 510) | type Track struct
    method Tag (line 122) | func (self Track) Tag() Tag {
    method Marshal (line 517) | func (self Track) Marshal(b []byte) (n int) {
    method marshal (line 523) | func (self Track) marshal(b []byte) (n int) {
    method Len (line 535) | func (self Track) Len() (n int) {
    method Unmarshal (line 548) | func (self *Track) Unmarshal(b []byte, offset int) (n int, err error) {
    method Children (line 591) | func (self Track) Children() (r []Atom) {
  type TrackHeader (line 602) | type TrackHeader struct
    method Tag (line 194) | func (self TrackHeader) Tag() Tag {
    method Marshal (line 618) | func (self TrackHeader) Marshal(b []byte) (n int) {
    method marshal (line 624) | func (self TrackHeader) marshal(b []byte) (n int) {
    method Len (line 656) | func (self TrackHeader) Len() (n int) {
    method Unmarshal (line 675) | func (self *TrackHeader) Unmarshal(b []byte, offset int) (n int, err e...
    method Children (line 757) | func (self TrackHeader) Children() (r []Atom) {
  type HandlerRefer (line 761) | type HandlerRefer struct
    method Tag (line 14) | func (self HandlerRefer) Tag() Tag {
    method Marshal (line 770) | func (self HandlerRefer) Marshal(b []byte) (n int) {
    method marshal (line 776) | func (self HandlerRefer) marshal(b []byte) (n int) {
    method Len (line 789) | func (self HandlerRefer) Len() (n int) {
    method Unmarshal (line 798) | func (self *HandlerRefer) Unmarshal(b []byte, offset int) (n int, err ...
    method Children (line 829) | func (self HandlerRefer) Children() (r []Atom) {
  type Media (line 833) | type Media struct
    method Tag (line 128) | func (self Media) Tag() Tag {
    method Marshal (line 841) | func (self Media) Marshal(b []byte) (n int) {
    method marshal (line 847) | func (self Media) marshal(b []byte) (n int) {
    method Len (line 862) | func (self Media) Len() (n int) {
    method Unmarshal (line 878) | func (self *Media) Unmarshal(b []byte, offset int) (n int, err error) {
    method Children (line 930) | func (self Media) Children() (r []Atom) {
  type MediaHeader (line 944) | type MediaHeader struct
    method Tag (line 44) | func (self MediaHeader) Tag() Tag {
    method Marshal (line 956) | func (self MediaHeader) Marshal(b []byte) (n int) {
    method marshal (line 962) | func (self MediaHeader) marshal(b []byte) (n int) {
    method Len (line 981) | func (self MediaHeader) Len() (n int) {
    method Unmarshal (line 993) | func (self *MediaHeader) Unmarshal(b []byte, offset int) (n int, err e...
    method Children (line 1046) | func (self MediaHeader) Children() (r []Atom) {
  type MediaInfo (line 1050) | type MediaInfo struct
    method Tag (line 74) | func (self MediaInfo) Tag() Tag {
    method Marshal (line 1059) | func (self MediaInfo) Marshal(b []byte) (n int) {
    method marshal (line 1065) | func (self MediaInfo) marshal(b []byte) (n int) {
    method Len (line 1083) | func (self MediaInfo) Len() (n int) {
    method Unmarshal (line 1102) | func (self *MediaInfo) Unmarshal(b []byte, offset int) (n int, err err...
    method Children (line 1163) | func (self MediaInfo) Children() (r []Atom) {
  type DataInfo (line 1180) | type DataInfo struct
    method Tag (line 164) | func (self DataInfo) Tag() Tag {
    method Marshal (line 1186) | func (self DataInfo) Marshal(b []byte) (n int) {
    method marshal (line 1192) | func (self DataInfo) marshal(b []byte) (n int) {
    method Len (line 1201) | func (self DataInfo) Len() (n int) {
    method Unmarshal (line 1211) | func (self *DataInfo) Unmarshal(b []byte, offset int) (n int, err erro...
    method Children (line 1245) | func (self DataInfo) Children() (r []Atom) {
  type DataRefer (line 1253) | type DataRefer struct
    method Tag (line 170) | func (self DataRefer) Tag() Tag {
    method Marshal (line 1260) | func (self DataRefer) Marshal(b []byte) (n int) {
    method marshal (line 1266) | func (self DataRefer) marshal(b []byte) (n int) {
    method Len (line 1282) | func (self DataRefer) Len() (n int) {
    method Unmarshal (line 1292) | func (self *DataRefer) Unmarshal(b []byte, offset int) (n int, err err...
    method Children (line 1330) | func (self DataRefer) Children() (r []Atom) {
  type DataReferUrl (line 1337) | type DataReferUrl struct
    method Tag (line 26) | func (self DataReferUrl) Tag() Tag {
    method Marshal (line 1343) | func (self DataReferUrl) Marshal(b []byte) (n int) {
    method marshal (line 1349) | func (self DataReferUrl) marshal(b []byte) (n int) {
    method Len (line 1356) | func (self DataReferUrl) Len() (n int) {
    method Unmarshal (line 1362) | func (self *DataReferUrl) Unmarshal(b []byte, offset int) (n int, err ...
    method Children (line 1379) | func (self DataReferUrl) Children() (r []Atom) {
  type SoundMediaInfo (line 1383) | type SoundMediaInfo struct
    method Tag (line 200) | func (self SoundMediaInfo) Tag() Tag {
    method Marshal (line 1390) | func (self SoundMediaInfo) Marshal(b []byte) (n int) {
    method marshal (line 1396) | func (self SoundMediaInfo) marshal(b []byte) (n int) {
    method Len (line 1406) | func (self SoundMediaInfo) Len() (n int) {
    method Unmarshal (line 1414) | func (self *SoundMediaInfo) Unmarshal(b []byte, offset int) (n int, er...
    method Children (line 1438) | func (self SoundMediaInfo) Children() (r []Atom) {
  type VideoMediaInfo (line 1442) | type VideoMediaInfo struct
    method Tag (line 140) | func (self VideoMediaInfo) Tag() Tag {
    method Marshal (line 1450) | func (self VideoMediaInfo) Marshal(b []byte) (n int) {
    method marshal (line 1456) | func (self VideoMediaInfo) marshal(b []byte) (n int) {
    method Len (line 1469) | func (self VideoMediaInfo) Len() (n int) {
    method Unmarshal (line 1477) | func (self *VideoMediaInfo) Unmarshal(b []byte, offset int) (n int, er...
    method Children (line 1508) | func (self VideoMediaInfo) Children() (r []Atom) {
  type SampleTable (line 1512) | type SampleTable struct
    method Tag (line 146) | func (self SampleTable) Tag() Tag {
    method Marshal (line 1523) | func (self SampleTable) Marshal(b []byte) (n int) {
    method marshal (line 1529) | func (self SampleTable) marshal(b []byte) (n int) {
    method Len (line 1553) | func (self SampleTable) Len() (n int) {
    method Unmarshal (line 1578) | func (self *SampleTable) Unmarshal(b []byte, offset int) (n int, err e...
    method Children (line 1657) | func (self SampleTable) Children() (r []Atom) {
  type SampleDesc (line 1682) | type SampleDesc struct
    method Tag (line 92) | func (self SampleDesc) Tag() Tag {
    method Marshal (line 1690) | func (self SampleDesc) Marshal(b []byte) (n int) {
    method marshal (line 1696) | func (self SampleDesc) marshal(b []byte) (n int) {
    method Len (line 1721) | func (self SampleDesc) Len() (n int) {
    method Unmarshal (line 1737) | func (self *SampleDesc) Unmarshal(b []byte, offset int) (n int, err er...
    method Children (line 1788) | func (self SampleDesc) Children() (r []Atom) {
  type MP4ADesc (line 1799) | type MP4ADesc struct
    method Tag (line 98) | func (self MP4ADesc) Tag() Tag {
    method Marshal (line 1813) | func (self MP4ADesc) Marshal(b []byte) (n int) {
    method marshal (line 1819) | func (self MP4ADesc) marshal(b []byte) (n int) {
    method Len (line 1846) | func (self MP4ADesc) Len() (n int) {
    method Unmarshal (line 1866) | func (self *MP4ADesc) Unmarshal(b []byte, offset int) (n int, err erro...
    method Children (line 1950) | func (self MP4ADesc) Children() (r []Atom) {
  type AVC1Desc (line 1958) | type AVC1Desc struct
    method Tag (line 20) | func (self AVC1Desc) Tag() Tag {
    method Marshal (line 1978) | func (self AVC1Desc) Marshal(b []byte) (n int) {
    method marshal (line 1984) | func (self AVC1Desc) marshal(b []byte) (n int) {
    method Len (line 2023) | func (self AVC1Desc) Len() (n int) {
    method Unmarshal (line 2049) | func (self *AVC1Desc) Unmarshal(b []byte, offset int) (n int, err erro...
    method Children (line 2169) | func (self AVC1Desc) Children() (r []Atom) {
  type AVC1Conf (line 2177) | type AVC1Conf struct
    method Tag (line 152) | func (self AVC1Conf) Tag() Tag {
    method Marshal (line 2182) | func (self AVC1Conf) Marshal(b []byte) (n int) {
    method marshal (line 2188) | func (self AVC1Conf) marshal(b []byte) (n int) {
    method Len (line 2193) | func (self AVC1Conf) Len() (n int) {
    method Unmarshal (line 2198) | func (self *AVC1Conf) Unmarshal(b []byte, offset int) (n int, err erro...
    method Children (line 2205) | func (self AVC1Conf) Children() (r []Atom) {
  type TimeToSample (line 2209) | type TimeToSample struct
    method Tag (line 50) | func (self TimeToSample) Tag() Tag {
    method Marshal (line 2216) | func (self TimeToSample) Marshal(b []byte) (n int) {
    method marshal (line 2222) | func (self TimeToSample) marshal(b []byte) (n int) {
    method Len (line 2235) | func (self TimeToSample) Len() (n int) {
    method Unmarshal (line 2243) | func (self *TimeToSample) Unmarshal(b []byte, offset int) (n int, err ...
    method Children (line 2272) | func (self TimeToSample) Children() (r []Atom) {
  type TimeToSampleEntry (line 2276) | type TimeToSampleEntry struct
  function GetTimeToSampleEntry (line 2281) | func GetTimeToSampleEntry(b []byte) (self TimeToSampleEntry) {
  function PutTimeToSampleEntry (line 2286) | func PutTimeToSampleEntry(b []byte, self TimeToSampleEntry) {
  constant LenTimeToSampleEntry (line 2291) | LenTimeToSampleEntry = 8
  type SampleToChunk (line 2293) | type SampleToChunk struct
    method Tag (line 134) | func (self SampleToChunk) Tag() Tag {
    method Marshal (line 2300) | func (self SampleToChunk) Marshal(b []byte) (n int) {
    method marshal (line 2306) | func (self SampleToChunk) marshal(b []byte) (n int) {
    method Len (line 2319) | func (self SampleToChunk) Len() (n int) {
    method Unmarshal (line 2327) | func (self *SampleToChunk) Unmarshal(b []byte, offset int) (n int, err...
    method Children (line 2356) | func (self SampleToChunk) Children() (r []Atom) {
  type SampleToChunkEntry (line 2360) | type SampleToChunkEntry struct
  function GetSampleToChunkEntry (line 2366) | func GetSampleToChunkEntry(b []byte) (self SampleToChunkEntry) {
  function PutSampleToChunkEntry (line 2372) | func PutSampleToChunkEntry(b []byte, self SampleToChunkEntry) {
  constant LenSampleToChunkEntry (line 2378) | LenSampleToChunkEntry = 12
  type CompositionOffset (line 2380) | type CompositionOffset struct
    method Tag (line 104) | func (self CompositionOffset) Tag() Tag {
    method Marshal (line 2387) | func (self CompositionOffset) Marshal(b []byte) (n int) {
    method marshal (line 2393) | func (self CompositionOffset) marshal(b []byte) (n int) {
    method Len (line 2406) | func (self CompositionOffset) Len() (n int) {
    method Unmarshal (line 2414) | func (self *CompositionOffset) Unmarshal(b []byte, offset int) (n int,...
    method Children (line 2443) | func (self CompositionOffset) Children() (r []Atom) {
  type CompositionOffsetEntry (line 2447) | type CompositionOffsetEntry struct
  function GetCompositionOffsetEntry (line 2452) | func GetCompositionOffsetEntry(b []byte) (self CompositionOffsetEntry) {
  function PutCompositionOffsetEntry (line 2457) | func PutCompositionOffsetEntry(b []byte, self CompositionOffsetEntry) {
  constant LenCompositionOffsetEntry (line 2462) | LenCompositionOffsetEntry = 8
  type SyncSample (line 2464) | type SyncSample struct
    method Tag (line 56) | func (self SyncSample) Tag() Tag {
    method Marshal (line 2471) | func (self SyncSample) Marshal(b []byte) (n int) {
    method marshal (line 2477) | func (self SyncSample) marshal(b []byte) (n int) {
    method Len (line 2490) | func (self SyncSample) Len() (n int) {
    method Unmarshal (line 2498) | func (self *SyncSample) Unmarshal(b []byte, offset int) (n int, err er...
    method Children (line 2527) | func (self SyncSample) Children() (r []Atom) {
  type ChunkOffset (line 2531) | type ChunkOffset struct
    method Tag (line 110) | func (self ChunkOffset) Tag() Tag {
    method Marshal (line 2538) | func (self ChunkOffset) Marshal(b []byte) (n int) {
    method marshal (line 2544) | func (self ChunkOffset) marshal(b []byte) (n int) {
    method Len (line 2557) | func (self ChunkOffset) Len() (n int) {
    method Unmarshal (line 2565) | func (self *ChunkOffset) Unmarshal(b []byte, offset int) (n int, err e...
    method Children (line 2594) | func (self ChunkOffset) Children() (r []Atom) {
  type MovieFrag (line 2598) | type MovieFrag struct
    method Tag (line 8) | func (self MovieFrag) Tag() Tag {
    method Marshal (line 2605) | func (self MovieFrag) Marshal(b []byte) (n int) {
    method marshal (line 2611) | func (self MovieFrag) marshal(b []byte) (n int) {
    method Len (line 2623) | func (self MovieFrag) Len() (n int) {
    method Unmarshal (line 2636) | func (self *MovieFrag) Unmarshal(b []byte, offset int) (n int, err err...
    method Children (line 2679) | func (self MovieFrag) Children() (r []Atom) {
  type MovieFragHeader (line 2690) | type MovieFragHeader struct
    method Tag (line 62) | func (self MovieFragHeader) Tag() Tag {
    method Marshal (line 2697) | func (self MovieFragHeader) Marshal(b []byte) (n int) {
    method marshal (line 2703) | func (self MovieFragHeader) marshal(b []byte) (n int) {
    method Len (line 2712) | func (self MovieFragHeader) Len() (n int) {
    method Unmarshal (line 2719) | func (self *MovieFragHeader) Unmarshal(b []byte, offset int) (n int, e...
    method Children (line 2742) | func (self MovieFragHeader) Children() (r []Atom) {
  type TrackFrag (line 2746) | type TrackFrag struct
    method Tag (line 176) | func (self TrackFrag) Tag() Tag {
    method Marshal (line 2754) | func (self TrackFrag) Marshal(b []byte) (n int) {
    method marshal (line 2760) | func (self TrackFrag) marshal(b []byte) (n int) {
    method Len (line 2775) | func (self TrackFrag) Len() (n int) {
    method Unmarshal (line 2791) | func (self *TrackFrag) Unmarshal(b []byte, offset int) (n int, err err...
    method Children (line 2843) | func (self TrackFrag) Children() (r []Atom) {
  type MovieExtend (line 2857) | type MovieExtend struct
    method Tag (line 86) | func (self MovieExtend) Tag() Tag {
    method Marshal (line 2863) | func (self MovieExtend) Marshal(b []byte) (n int) {
    method marshal (line 2869) | func (self MovieExtend) marshal(b []byte) (n int) {
    method Len (line 2878) | func (self MovieExtend) Len() (n int) {
    method Unmarshal (line 2888) | func (self *MovieExtend) Unmarshal(b []byte, offset int) (n int, err e...
    method Children (line 2922) | func (self MovieExtend) Children() (r []Atom) {
  type TrackExtend (line 2930) | type TrackExtend struct
    method Tag (line 32) | func (self TrackExtend) Tag() Tag {
    method Marshal (line 2941) | func (self TrackExtend) Marshal(b []byte) (n int) {
    method marshal (line 2947) | func (self TrackExtend) marshal(b []byte) (n int) {
    method Len (line 2964) | func (self TrackExtend) Len() (n int) {
    method Unmarshal (line 2975) | func (self *TrackExtend) Unmarshal(b []byte, offset int) (n int, err e...
    method Children (line 3022) | func (self TrackExtend) Children() (r []Atom) {
  type SampleSize (line 3026) | type SampleSize struct
    method Tag (line 182) | func (self SampleSize) Tag() Tag {
    method Marshal (line 3034) | func (self SampleSize) Marshal(b []byte) (n int) {
    method marshal (line 3040) | func (self SampleSize) marshal(b []byte) (n int) {
    method Len (line 3058) | func (self SampleSize) Len() (n int) {
    method Unmarshal (line 3070) | func (self *SampleSize) Unmarshal(b []byte, offset int) (n int, err er...
    method Children (line 3108) | func (self SampleSize) Children() (r []Atom) {
  type TrackFragRun (line 3112) | type TrackFragRun struct
    method Tag (line 116) | func (self TrackFragRun) Tag() Tag {
    method Marshal (line 3121) | func (self TrackFragRun) Marshal(b []byte) (n int) {
    method marshal (line 3127) | func (self TrackFragRun) marshal(b []byte) (n int) {
    method Len (line 3173) | func (self TrackFragRun) Len() (n int) {
    method Unmarshal (line 3211) | func (self *TrackFragRun) Unmarshal(b []byte, offset int) (n int, err ...
    method Children (line 3278) | func (self TrackFragRun) Children() (r []Atom) {
  type TrackFragRunEntry (line 3282) | type TrackFragRunEntry struct
  function GetTrackFragRunEntry (line 3289) | func GetTrackFragRunEntry(b []byte) (self TrackFragRunEntry) {
  function PutTrackFragRunEntry (line 3296) | func PutTrackFragRunEntry(b []byte, self TrackFragRunEntry) {
  constant LenTrackFragRunEntry (line 3303) | LenTrackFragRunEntry = 16
  type TrackFragHeader (line 3305) | type TrackFragHeader struct
    method Tag (line 188) | func (self TrackFragHeader) Tag() Tag {
    method Marshal (line 3316) | func (self TrackFragHeader) Marshal(b []byte) (n int) {
    method marshal (line 3322) | func (self TrackFragHeader) marshal(b []byte) (n int) {
    method Len (line 3359) | func (self TrackFragHeader) Len() (n int) {
    method Unmarshal (line 3390) | func (self *TrackFragHeader) Unmarshal(b []byte, offset int) (n int, e...
    method Children (line 3457) | func (self TrackFragHeader) Children() (r []Atom) {
  type TrackFragDecodeTime (line 3461) | type TrackFragDecodeTime struct
    method Tag (line 158) | func (self TrackFragDecodeTime) Tag() Tag {
    method Marshal (line 3468) | func (self TrackFragDecodeTime) Marshal(b []byte) (n int) {
    method marshal (line 3474) | func (self TrackFragDecodeTime) marshal(b []byte) (n int) {
    method Len (line 3489) | func (self TrackFragDecodeTime) Len() (n int) {
    method Unmarshal (line 3501) | func (self *TrackFragDecodeTime) Unmarshal(b []byte, offset int) (n in...
    method Children (line 3526) | func (self TrackFragDecodeTime) Children() (r []Atom) {

FILE: format/mp4/mp4io/gen/gen.go
  function getexprs (line 14) | func getexprs(e ast.Expr) string {
  function genatomdecl (line 24) | func genatomdecl(origfn *ast.FuncDecl, origname, origtag string) (decls ...
  function typegetlen (line 107) | func typegetlen(typ string) (n int) {
  function typegetlens (line 135) | func typegetlens(typ string) string {
  function typegetvartype (line 144) | func typegetvartype(typ string) string {
  function typegetputfn (line 164) | func typegetputfn(typ string) (fn string) {
  function typegetgetfn (line 195) | func typegetgetfn(typ string) (fn string) {
  function addns (line 226) | func addns(n string) (stmts []ast.Stmt) {
  function addn (line 236) | func addn(n int) (stmts []ast.Stmt) {
  function simplecall (line 240) | func simplecall(fun string, args... string) *ast.ExprStmt {
  function getxx (line 253) | func getxx(typ string, pos, name string, conv bool) (stmts []ast.Stmt) {
  function putxx (line 264) | func putxx(typ string, pos, name string, conv bool) (stmts []ast.Stmt) {
  function putxxadd (line 273) | func putxxadd(fn string, name string, conv bool) (stmts []ast.Stmt) {
  function newdecl (line 280) | func newdecl(origname, name string, params, res []*ast.Field, stmts []as...
  function getstructputgetlenfn (line 303) | func getstructputgetlenfn(origfn *ast.FuncDecl, origname string) (decls ...
  function cc4decls (line 364) | func cc4decls(name string) (decls []ast.Decl) {
  function codeclonereplace (line 385) | func codeclonereplace(stmts []ast.Stmt, doit []ast.Stmt) (out []ast.Stmt) {
  function getatommarshalfn (line 412) | func getatommarshalfn(origfn *ast.FuncDecl,
  function genatoms (line 956) | func genatoms(filename, outfilename string) {
  function parse (line 1037) | func parse(filename, outfilename string) {
  function main (line 1048) | func main() {

FILE: format/mp4/mp4io/gen/pattern.go
  function moov_Movie (line 3) | func moov_Movie() {
  function mvhd_MovieHeader (line 10) | func mvhd_MovieHeader() {
  function trak_Track (line 30) | func trak_Track() {
  function tkhd_TrackHeader (line 36) | func tkhd_TrackHeader() {
  function hdlr_HandlerRefer (line 54) | func hdlr_HandlerRefer() {
  function mdia_Media (line 62) | func mdia_Media() {
  function mdhd_MediaHeader (line 69) | func mdhd_MediaHeader() {
  function minf_MediaInfo (line 80) | func minf_MediaInfo() {
  function dinf_DataInfo (line 88) | func dinf_DataInfo() {
  function dref_DataRefer (line 93) | func dref_DataRefer() {
  function url__DataReferUrl (line 100) | func url__DataReferUrl() {
  function smhd_SoundMediaInfo (line 105) | func smhd_SoundMediaInfo() {
  function vmhd_VideoMediaInfo (line 112) | func vmhd_VideoMediaInfo() {
  function stbl_SampleTable (line 119) | func stbl_SampleTable() {
  function stsd_SampleDesc (line 129) | func stsd_SampleDesc() {
  function mp4a_MP4ADesc (line 138) | func mp4a_MP4ADesc() {
  function avc1_AVC1Desc (line 153) | func avc1_AVC1Desc() {
  function avcC_AVC1Conf (line 174) | func avcC_AVC1Conf() {
  function stts_TimeToSample (line 178) | func stts_TimeToSample() {
  function TimeToSampleEntry (line 185) | func TimeToSampleEntry() {
  function stsc_SampleToChunk (line 190) | func stsc_SampleToChunk() {
  function SampleToChunkEntry (line 197) | func SampleToChunkEntry() {
  function ctts_CompositionOffset (line 203) | func ctts_CompositionOffset() {
  function CompositionOffsetEntry (line 210) | func CompositionOffsetEntry() {
  function stss_SyncSample (line 215) | func stss_SyncSample() {
  function stco_ChunkOffset (line 222) | func stco_ChunkOffset() {
  function moof_MovieFrag (line 229) | func moof_MovieFrag() {
  function mfhd_MovieFragHeader (line 235) | func mfhd_MovieFragHeader() {
  function traf_TrackFrag (line 241) | func traf_TrackFrag() {
  function mvex_MovieExtend (line 248) | func mvex_MovieExtend() {
  function trex_TrackExtend (line 253) | func trex_TrackExtend() {
  function stsz_SampleSize (line 263) | func stsz_SampleSize() {
  function trun_TrackFragRun (line 276) | func trun_TrackFragRun() {
  function TrackFragRunEntry (line 368) | func TrackFragRunEntry() {
  function tfhd_TrackFragHeader (line 375) | func tfhd_TrackFragHeader() {
  function tfdt_TrackFragDecodeTime (line 410) | func tfdt_TrackFragDecodeTime() {

FILE: format/mp4/mp4io/mp4io.go
  type ParseError (line 14) | type ParseError struct
    method Error (line 20) | func (self *ParseError) Error() string {
  function parseErr (line 28) | func parseErr(debug string, offset int, prev error) (err error) {
  function GetTime32 (line 33) | func GetTime32(b []byte) (t time.Time) {
  function PutTime32 (line 40) | func PutTime32(b []byte, t time.Time) {
  function GetTime64 (line 46) | func GetTime64(b []byte) (t time.Time) {
  function PutTime64 (line 53) | func PutTime64(b []byte, t time.Time) {
  function PutFixed16 (line 59) | func PutFixed16(b []byte, f float64) {
  function GetFixed16 (line 65) | func GetFixed16(b []byte) float64 {
  function PutFixed32 (line 69) | func PutFixed32(b []byte, f float64) {
  function GetFixed32 (line 75) | func GetFixed32(b []byte) float64 {
  type Tag (line 79) | type Tag
    method String (line 81) | func (self Tag) String() string {
  type Atom (line 92) | type Atom interface
  type AtomPos (line 101) | type AtomPos struct
    method Pos (line 106) | func (self AtomPos) Pos() (int,int) {
    method setPos (line 110) | func (self *AtomPos) setPos(offset int, size int) {
  type Dummy (line 114) | type Dummy struct
    method Children (line 120) | func (self Dummy) Children() []Atom {
    method Tag (line 124) | func (self Dummy) Tag() Tag {
    method Len (line 128) | func (self Dummy) Len() int {
    method Marshal (line 132) | func (self Dummy) Marshal(b []byte) int {
    method Unmarshal (line 137) | func (self *Dummy) Unmarshal(b []byte, offset int) (n int, err error) {
  function StringToTag (line 144) | func StringToTag(tag string) Tag {
  function FindChildrenByName (line 150) | func FindChildrenByName(root Atom, tag string) Atom {
  function FindChildren (line 154) | func FindChildren(root Atom, tag Tag) Atom {
  constant TFHD_BASE_DATA_OFFSET (line 167) | TFHD_BASE_DATA_OFFSET     = 0x01
  constant TFHD_STSD_ID (line 168) | TFHD_STSD_ID              = 0x02
  constant TFHD_DEFAULT_DURATION (line 169) | TFHD_DEFAULT_DURATION     = 0x08
  constant TFHD_DEFAULT_SIZE (line 170) | TFHD_DEFAULT_SIZE         = 0x10
  constant TFHD_DEFAULT_FLAGS (line 171) | TFHD_DEFAULT_FLAGS        = 0x20
  constant TFHD_DURATION_IS_EMPTY (line 172) | TFHD_DURATION_IS_EMPTY    = 0x010000
  constant TFHD_DEFAULT_BASE_IS_MOOF (line 173) | TFHD_DEFAULT_BASE_IS_MOOF = 0x020000
  constant TRUN_DATA_OFFSET (line 177) | TRUN_DATA_OFFSET        = 0x01
  constant TRUN_FIRST_SAMPLE_FLAGS (line 178) | TRUN_FIRST_SAMPLE_FLAGS = 0x04
  constant TRUN_SAMPLE_DURATION (line 179) | TRUN_SAMPLE_DURATION    = 0x100
  constant TRUN_SAMPLE_SIZE (line 180) | TRUN_SAMPLE_SIZE        = 0x200
  constant TRUN_SAMPLE_FLAGS (line 181) | TRUN_SAMPLE_FLAGS       = 0x400
  constant TRUN_SAMPLE_CTS (line 182) | TRUN_SAMPLE_CTS         = 0x800
  constant MP4ESDescrTag (line 186) | MP4ESDescrTag          = 3
  constant MP4DecConfigDescrTag (line 187) | MP4DecConfigDescrTag   = 4
  constant MP4DecSpecificDescrTag (line 188) | MP4DecSpecificDescrTag = 5
  type ElemStreamDesc (line 191) | type ElemStreamDesc struct
    method Children (line 197) | func (self ElemStreamDesc) Children() []Atom {
    method fillLength (line 201) | func (self ElemStreamDesc) fillLength(b []byte, length int) (n int) {
    method lenDescHdr (line 211) | func (self ElemStreamDesc) lenDescHdr() (n int) {
    method fillDescHdr (line 215) | func (self ElemStreamDesc) fillDescHdr(b []byte, tag uint8, datalen in...
    method lenESDescHdr (line 222) | func (self ElemStreamDesc) lenESDescHdr() (n int) {
    method fillESDescHdr (line 226) | func (self ElemStreamDesc) fillESDescHdr(b []byte, datalen int) (n int) {
    method lenDecConfigDescHdr (line 235) | func (self ElemStreamDesc) lenDecConfigDescHdr() (n int) {
    method fillDecConfigDescHdr (line 239) | func (self ElemStreamDesc) fillDecConfigDescHdr(b []byte, datalen int)...
    method Len (line 258) | func (self ElemStreamDesc) Len() (n int) {
    method Marshal (line 278) | func (self ElemStreamDesc) Marshal(b []byte) (n int) {
    method Unmarshal (line 295) | func (self *ElemStreamDesc) Unmarshal(b []byte, offset int) (n int, er...
    method parseDesc (line 306) | func (self *ElemStreamDesc) parseDesc(b []byte, offset int) (n int, er...
    method parseLength (line 348) | func (self *ElemStreamDesc) parseLength(b []byte, offset int) (n int, ...
    method parseDescHdr (line 364) | func (self *ElemStreamDesc) parseDescHdr(b []byte, offset int) (n int,...
    method String (line 488) | func (self ElemStreamDesc) String() string {
  function ReadFileAtoms (line 379) | func ReadFileAtoms(r io.ReadSeeker) (atoms []Atom, err error) {
  function printatom (line 422) | func printatom(out io.Writer, root Atom, depth int) {
  function FprintAtom (line 444) | func FprintAtom(out io.Writer, root Atom) {
  function PrintAtom (line 448) | func PrintAtom(root Atom) {
  method String (line 452) | func (self MovieHeader) String() string {
  method String (line 456) | func (self TimeToSample) String() string {
  method String (line 460) | func (self SampleToChunk) String() string {
  method String (line 464) | func (self SampleSize) String() string {
  method String (line 468) | func (self SyncSample) String() string {
  method String (line 472) | func (self CompositionOffset) String() string {
  method String (line 476) | func (self ChunkOffset) String() string {
  method String (line 480) | func (self TrackFragRun) String() string {
  method String (line 484) | func (self TrackFragHeader) String() string {
  method GetAVC1Conf (line 492) | func (self *Track) GetAVC1Conf() (conf *AVC1Conf) {
  method GetElemStreamDesc (line 498) | func (self *Track) GetElemStreamDesc() (esds *ElemStreamDesc) {

FILE: format/mp4/muxer.go
  type Muxer (line 15) | type Muxer struct
    method newStream (line 29) | func (self *Muxer) newStream(codec av.CodecData) (err error) {
    method WriteHeader (line 147) | func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) {
    method WritePacket (line 170) | func (self *Muxer) WritePacket(pkt av.Packet) (err error) {
    method WriteTrailer (line 221) | func (self *Muxer) WriteTrailer() (err error) {
  function NewMuxer (line 22) | func NewMuxer(w io.WriteSeeker) *Muxer {
  method fillTrackAtom (line 93) | func (self *Stream) fillTrackAtom() (err error) {
  method writePacket (line 181) | func (self *Stream) writePacket(pkt av.Packet, rawdur time.Duration) (er...

FILE: format/mp4/stream.go
  type Stream (line 9) | type Stream struct
    method timeToTs (line 52) | func (self *Stream) timeToTs(tm time.Duration) int64 {
    method tsToTime (line 56) | func (self *Stream) tsToTime(ts int64) time.Duration {
  function timeToTs (line 44) | func timeToTs(tm time.Duration, timeScale int64) int64 {
  function tsToTime (line 48) | func tsToTime(ts int64, timeScale int64) time.Duration {

FILE: format/rtmp/rtmp.go
  function ParseURL (line 25) | func ParseURL(uri string) (u *url.URL, err error) {
  function Dial (line 35) | func Dial(uri string) (conn *Conn, err error) {
  function DialTimeout (line 39) | func DialTimeout(uri string, timeout time.Duration) (conn *Conn, err err...
  type Server (line 56) | type Server struct
    method handleConn (line 63) | func (self *Server) handleConn(conn *Conn) (err error) {
    method ListenAndServe (line 85) | func (self *Server) ListenAndServe() (err error) {
  constant stageHandshakeDone (line 127) | stageHandshakeDone = iota + 1
  constant stageCommandDone (line 128) | stageCommandDone
  constant stageCodecDataDone (line 129) | stageCodecDataDone
  constant prepareReading (line 133) | prepareReading = iota + 1
  constant prepareWriting (line 134) | prepareWriting
  type Conn (line 137) | type Conn struct
    method NetConn (line 255) | func (self *Conn) NetConn() net.Conn {
    method TxBytes (line 259) | func (self *Conn) TxBytes() uint64 {
    method RxBytes (line 263) | func (self *Conn) RxBytes() uint64 {
    method Close (line 267) | func (self *Conn) Close() (err error) {
    method pollCommand (line 271) | func (self *Conn) pollCommand() (err error) {
    method pollAVTag (line 282) | func (self *Conn) pollAVTag() (tag flvio.Tag, err error) {
    method pollMsg (line 295) | func (self *Conn) pollMsg() (err error) {
    method writeBasicConf (line 354) | func (self *Conn) writeBasicConf() (err error) {
    method readConnect (line 370) | func (self *Conn) readConnect() (err error) {
    method checkConnectResult (line 541) | func (self *Conn) checkConnectResult() (ok bool, errmsg string) {
    method checkCreateStreamResult (line 569) | func (self *Conn) checkCreateStreamResult() (ok bool, avmsgsid uint32) {
    method probe (line 580) | func (self *Conn) probe() (err error) {
    method writeConnect (line 596) | func (self *Conn) writeConnect(path string) (err error) {
    method connectPublish (line 657) | func (self *Conn) connectPublish() (err error) {
    method connectPlay (line 715) | func (self *Conn) connectPlay() (err error) {
    method ReadPacket (line 773) | func (self *Conn) ReadPacket() (pkt av.Packet, err error) {
    method Prepare (line 798) | func (self *Conn) Prepare() (err error) {
    method prepare (line 802) | func (self *Conn) prepare(stage int, flags int) (err error) {
    method Streams (line 847) | func (self *Conn) Streams() (streams []av.CodecData, err error) {
    method WritePacket (line 855) | func (self *Conn) WritePacket(pkt av.Packet) (err error) {
    method WriteTrailer (line 874) | func (self *Conn) WriteTrailer() (err error) {
    method WriteHeader (line 881) | func (self *Conn) WriteHeader(streams []av.CodecData) (err error) {
    method tmpwbuf (line 916) | func (self *Conn) tmpwbuf(n int) []byte {
    method writeSetChunkSize (line 923) | func (self *Conn) writeSetChunkSize(size int) (err error) {
    method writeAck (line 933) | func (self *Conn) writeAck(seqnum uint32) (err error) {
    method writeWindowAckSize (line 942) | func (self *Conn) writeWindowAckSize(size uint32) (err error) {
    method writeSetPeerBandwidth (line 951) | func (self *Conn) writeSetPeerBandwidth(acksize uint32, limittype uint...
    method writeCommandMsg (line 962) | func (self *Conn) writeCommandMsg(csid, msgsid uint32, args ...interfa...
    method writeDataMsg (line 966) | func (self *Conn) writeDataMsg(csid, msgsid uint32, args ...interface{...
    method writeAMF0Msg (line 970) | func (self *Conn) writeAMF0Msg(msgtypeid uint8, csid, msgsid uint32, a...
    method writeAVTag (line 986) | func (self *Conn) writeAVTag(tag flvio.Tag, ts int32) (err error) {
    method writeStreamBegin (line 1026) | func (self *Conn) writeStreamBegin(msgsid uint32) (err error) {
    method writeSetBufferLength (line 1037) | func (self *Conn) writeSetBufferLength(msgsid uint32, timestamp uint32...
    method fillChunkHeader (line 1053) | func (self *Conn) fillChunkHeader(b []byte, csid uint32, timestamp int...
    method flushWrite (line 1092) | func (self *Conn) flushWrite() (err error) {
    method readChunk (line 1099) | func (self *Conn) readChunk() (err error) {
    method handleCommandMsgAMF0 (line 1319) | func (self *Conn) handleCommandMsgAMF0(b []byte) (n int, err error) {
    method handleMsg (line 1361) | func (self *Conn) handleMsg(timestamp uint32, msgsid uint32, msgtypeid...
    method handshakeClient (line 1526) | func (self *Conn) handshakeClient() (err error) {
    method handshakeServer (line 1576) | func (self *Conn) handshakeServer() (err error) {
  type txrxcount (line 185) | type txrxcount struct
    method Read (line 191) | func (self *txrxcount) Read(p []byte) (int, error) {
    method Write (line 197) | func (self *txrxcount) Write(p []byte) (int, error) {
  function NewConn (line 203) | func NewConn(netconn net.Conn) *Conn {
  type chunkStream (line 218) | type chunkStream struct
    method Start (line 230) | func (self *chunkStream) Start() {
  constant msgtypeidUserControl (line 236) | msgtypeidUserControl      = 4
  constant msgtypeidAck (line 237) | msgtypeidAck              = 3
  constant msgtypeidWindowAckSize (line 238) | msgtypeidWindowAckSize    = 5
  constant msgtypeidSetPeerBandwidth (line 239) | msgtypeidSetPeerBandwidth = 6
  constant msgtypeidSetChunkSize (line 240) | msgtypeidSetChunkSize     = 1
  constant msgtypeidCommandMsgAMF0 (line 241) | msgtypeidCommandMsgAMF0   = 20
  constant msgtypeidCommandMsgAMF3 (line 242) | msgtypeidCommandMsgAMF3   = 17
  constant msgtypeidDataMsgAMF0 (line 243) | msgtypeidDataMsgAMF0      = 18
  constant msgtypeidDataMsgAMF3 (line 244) | msgtypeidDataMsgAMF3      = 15
  constant msgtypeidVideoMsg (line 245) | msgtypeidVideoMsg         = 9
  constant msgtypeidAudioMsg (line 246) | msgtypeidAudioMsg         = 8
  constant eventtypeStreamBegin (line 250) | eventtypeStreamBegin      = 0
  constant eventtypeSetBufferLength (line 251) | eventtypeSetBufferLength  = 3
  constant eventtypeStreamIsRecorded (line 252) | eventtypeStreamIsRecorded = 4
  function SplitPath (line 310) | func SplitPath(u *url.URL) (app, stream string) {
  function getTcUrl (line 321) | func getTcUrl(u *url.URL) string {
  function createURL (line 328) | func createURL(tcurl, app, play string) (u *url.URL) {
  constant chunkHeaderLength (line 1050) | chunkHeaderLength = 12
  constant FlvTimestampMax (line 1051) | FlvTimestampMax = 0xFFFFFF
  function hsMakeDigest (line 1468) | func hsMakeDigest(key []byte, src []byte, gap int) (dst []byte) {
  function hsCalcDigestPos (line 1479) | func hsCalcDigestPos(p []byte, base int) (pos int) {
  function hsFindDigest (line 1487) | func hsFindDigest(p []byte, key []byte, base int) int {
  function hsParse1 (line 1496) | func hsParse1(p []byte, peerkey []byte, key []byte) (ok bool, digest []b...
  function hsCreate01 (line 1508) | func hsCreate01(p []byte, time uint32, ver uint32, key []byte) {
  function hsCreate2 (line 1519) | func hsCreate2(p []byte, key []byte) {
  type closeConn (line 1638) | type closeConn struct
    method Close (line 1643) | func (self closeConn) Close() error {
  function Handler (line 1648) | func Handler(h *avutil.RegisterHandler) {

FILE: format/rtsp/client.go
  constant stageDescribeDone (line 34) | stageDescribeDone = iota+1
  constant stageSetupDone (line 35) | stageSetupDone
  constant stageWaitCodecData (line 36) | stageWaitCodecData
  constant stageCodecDataDone (line 37) | stageCodecDataDone
  type Client (line 40) | type Client struct
    method allCodecDataReady (line 123) | func (self *Client) allCodecDataReady() bool {
    method probe (line 133) | func (self *Client) probe() (err error) {
    method prepare (line 146) | func (self *Client) prepare(stage int) (err error) {
    method Streams (line 173) | func (self *Client) Streams() (streams []av.CodecData, err error) {
    method SendRtpKeepalive (line 184) | func (self *Client) SendRtpKeepalive() (err error) {
    method WriteRequest (line 205) | func (self *Client) WriteRequest(req Request) (err error) {
    method parseBlockHeader (line 244) | func (self *Client) parseBlockHeader(h []byte) (length int, no int, va...
    method parseHeaders (line 282) | func (self *Client) parseHeaders(b []byte) (statusCode int, headers te...
    method handleResp (line 301) | func (self *Client) handleResp(res *Response) (err error) {
    method handle401 (line 315) | func (self *Client) handle401(res *Response) (err error) {
    method findRTSP (line 374) | func (self *Client) findRTSP() (block []byte, data []byte, err error) {
    method readLFLF (line 452) | func (self *Client) readLFLF() (block []byte, data []byte, err error) {
    method readResp (line 507) | func (self *Client) readResp(b []byte) (res Response, err error) {
    method poll (line 524) | func (self *Client) poll() (res Response, err error) {
    method ReadResponse (line 555) | func (self *Client) ReadResponse() (res Response, err error) {
    method SetupAll (line 567) | func (self *Client) SetupAll() (err error) {
    method Setup (line 575) | func (self *Client) Setup(idx []int) (err error) {
    method Describe (line 620) | func (self *Client) Describe() (streams []sdp.Media, err error) {
    method Options (line 666) | func (self *Client) Options() (err error) {
    method HandleCodecDataChange (line 683) | func (self *Client) HandleCodecDataChange() (_newcli *Client, err erro...
    method Play (line 1101) | func (self *Client) Play() (err error) {
    method Teardown (line 1119) | func (self *Client) Teardown() (err error) {
    method Close (line 1131) | func (self *Client) Close() (err error) {
    method handleBlock (line 1135) | func (self *Client) handleBlock(block []byte) (pkt av.Packet, ok bool,...
    method readPacket (line 1194) | func (self *Client) readPacket() (pkt av.Packet, err error) {
    method ReadPacket (line 1222) | func (self *Client) ReadPacket() (pkt av.Packet, err error) {
  type Request (line 71) | type Request struct
  type Response (line 77) | type Response struct
  function DialTimeout (line 86) | func DialTimeout(uri string, timeout time.Duration) (self *Client, err e...
  function Dial (line 119) | func Dial(uri string) (self *Client, err error) {
  function md5hash (line 615) | func md5hash(s string) string {
  method clearCodecDataChange (line 706) | func (self *Stream) clearCodecDataChange() {
  method isCodecDataChange (line 711) | func (self *Stream) isCodecDataChange() bool {
  method timeScale (line 718) | func (self *Stream) timeScale() int {
  method makeCodecData (line 727) | func (self *Stream) makeCodecData() (err error) {
  method handleBuggyAnnexbH264Packet (line 786) | func (self *Stream) handleBuggyAnnexbH264Packet(timestamp uint32, packet...
  method handleH264Payload (line 802) | func (self *Stream) handleH264Payload(timestamp uint32, packet []byte) (...
  method handleRtpPacket (line 991) | func (self *Stream) handleRtpPacket(packet []byte) (err error) {
  function Handler (line 1229) | func Handler(h *avutil.RegisterHandler) {

FILE: format/rtsp/conn.go
  type connWithTimeout (line 8) | type connWithTimeout struct
    method Read (line 13) | func (self connWithTimeout) Read(p []byte) (n int, err error) {
    method Write (line 20) | func (self connWithTimeout) Write(p []byte) (n int, err error) {

FILE: format/rtsp/sdp/parser.go
  type Session (line 12) | type Session struct
  type Media (line 16) | type Media struct
  function Parse (line 29) | func Parse(content string) (sess Session, medias []Media) {

FILE: format/rtsp/sdp/parser_test.go
  function TestParse (line 7) | func TestParse(t *testing.T) {

FILE: format/rtsp/stream.go
  type Stream (line 9) | type Stream struct

FILE: format/ts/demuxer.go
  type Demuxer (line 15) | type Demuxer struct
    method Streams (line 35) | func (self *Demuxer) Streams() (streams []av.CodecData, err error) {
    method probe (line 45) | func (self *Demuxer) probe() (err error) {
    method ReadPacket (line 68) | func (self *Demuxer) ReadPacket() (pkt av.Packet, err error) {
    method poll (line 84) | func (self *Demuxer) poll() (err error) {
    method initPMT (line 97) | func (self *Demuxer) initPMT(payload []byte) (err error) {
    method payloadEnd (line 125) | func (self *Demuxer) payloadEnd() (n int, err error) {
    method readTSPacket (line 136) | func (self *Demuxer) readTSPacket() (err error) {
  function NewDemuxer (line 28) | func NewDemuxer(r io.Reader) *Demuxer {
  method addPacket (line 186) | func (self *Stream) addPacket(payload []byte, timedelta time.Duration) {
  method payloadEnd (line 206) | func (self *Stream) payloadEnd() (n int, err error) {
  method handleTSPacket (line 270) | func (self *Stream) handleTSPacket(start bool, iskeyframe bool, payload ...

FILE: format/ts/handler.go
  function Handler (line 9) | func Handler(h *avutil.RegisterHandler) {

FILE: format/ts/muxer.go
  type Muxer (line 15) | type Muxer struct
    method newStream (line 44) | func (self *Muxer) newStream(codec av.CodecData) (err error) {
    method writePaddingTSPackets (line 68) | func (self *Muxer) writePaddingTSPackets(tsw *tsio.TSWriter) (err erro...
    method WriteTrailer (line 77) | func (self *Muxer) WriteTrailer() (err error) {
    method SetWriter (line 88) | func (self *Muxer) SetWriter(w io.Writer) {
    method WritePATPMT (line 93) | func (self *Muxer) WritePATPMT() (err error) {
    method WriteHeader (line 141) | func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) {
    method WritePacket (line 155) | func (self *Muxer) WritePacket(pkt av.Packet) (err error) {
  function NewMuxer (line 30) | func NewMuxer(w io.Writer) *Muxer {

FILE: format/ts/stream.go
  type Stream (line 9) | type Stream struct

FILE: format/ts/tsio/checksum.go
  function calcCRC32 (line 49) | func calcCRC32(crc uint32, data []byte) uint32 {

FILE: format/ts/tsio/tsio.go
  constant StreamIdH264 (line 12) | StreamIdH264 = 0xe0
  constant StreamIdAAC (line 13) | StreamIdAAC  = 0xc0
  constant PAT_PID (line 17) | PAT_PID = 0
  constant PMT_PID (line 18) | PMT_PID = 0x1000
  constant TableIdPMT (line 21) | TableIdPMT = 2
  constant TableExtPMT (line 22) | TableExtPMT = 1
  constant TableIdPAT (line 24) | TableIdPAT = 0
  constant TableExtPAT (line 25) | TableExtPAT = 1
  constant MaxPESHeaderLength (line 27) | MaxPESHeaderLength = 19
  constant MaxTSHeaderLength (line 28) | MaxTSHeaderLength = 12
  constant ElementaryStreamTypeH264 (line 36) | ElementaryStreamTypeH264    = 0x1B
  constant ElementaryStreamTypeAdtsAAC (line 37) | ElementaryStreamTypeAdtsAAC = 0x0F
  type PATEntry (line 40) | type PATEntry struct
  type PAT (line 46) | type PAT struct
    method Len (line 50) | func (self PAT) Len() (n int) {
    method Marshal (line 54) | func (self PAT) Marshal(b []byte) (n int) {
    method Unmarshal (line 69) | func (self *PAT) Unmarshal(b []byte) (n int, err error) {
  type Descriptor (line 94) | type Descriptor struct
  type ElementaryStreamInfo (line 99) | type ElementaryStreamInfo struct
  type PMT (line 105) | type PMT struct
    method Len (line 111) | func (self PMT) Len() (n int) {
    method fillDescs (line 143) | func (self PMT) fillDescs(b []byte, descs []Descriptor) (n int) {
    method Marshal (line 155) | func (self PMT) Marshal(b []byte) (n int) {
    method parseDescs (line 188) | func (self PMT) parseDescs(b []byte) (descs []Descriptor, err error) {
    method Unmarshal (line 214) | func (self *PMT) Unmarshal(b []byte) (n int, err error) {
  function ParsePSI (line 279) | func ParsePSI(h []byte) (tableid uint8, tableext uint16, hdrlen int, dat...
  constant PSIHeaderLength (line 336) | PSIHeaderLength = 9
  function FillPSI (line 338) | func FillPSI(h []byte, tableid uint8, tableext uint16, datalen int) (n i...
  function TimeToPCR (line 376) | func TimeToPCR(tm time.Duration) (pcr uint64) {
  function PCRToTime (line 385) | func PCRToTime(pcr uint64) (tm time.Duration) {
  function TimeToTs (line 393) | func TimeToTs(tm time.Duration) (v uint64) {
  function TsToTime (line 400) | func TsToTime(v uint64) (tm time.Duration) {
  constant PTS_HZ (line 408) | PTS_HZ = 90000
  constant PCR_HZ (line 409) | PCR_HZ = 27000000
  function ParsePESHeader (line 412) | func ParsePESHeader(h []byte) (hdrlen int, streamid uint8, datalen int, ...
  function FillPESHeader (line 448) | func FillPESHeader(h []byte, streamid uint8, datalen int, pts, dts time....
  type TSWriter (line 501) | type TSWriter struct
    method WritePackets (line 518) | func (self *TSWriter) WritePackets(w io.Writer, datav [][]byte, pcr ti...
  function NewTSWriter (line 507) | func NewTSWriter(pid uint16) *TSWriter {
  function ParseTSHeader (line 575) | func ParseTSHeader(tshdr []byte) (pid uint16, start bool, iskeyframe boo...

FILE: utils/bits/bits.go
  type Reader (line 7) | type Reader struct
    method ReadBits64 (line 13) | func (self *Reader) ReadBits64(n int) (bits uint64, err error) {
    method ReadBits (line 37) | func (self *Reader) ReadBits(n int) (bits uint, err error) {
    method Read (line 46) | func (self *Reader) Read(p []byte) (n int, err error) {
  type Writer (line 64) | type Writer struct
    method WriteBits64 (line 70) | func (self *Writer) WriteBits64(bits uint64, n int) (err error) {
    method WriteBits (line 87) | func (self *Writer) WriteBits(bits uint, n int) (err error) {
    method Write (line 91) | func (self *Writer) Write(p []byte) (n int, err error) {
    method FlushBits (line 101) | func (self *Writer) FlushBits() (err error) {

FILE: utils/bits/bits_test.go
  function TestBits (line 8) | func TestBits(t *testing.T) {

FILE: utils/bits/bufio/bufio.go
  type Reader (line 7) | type Reader struct
    method ReadAt (line 20) | func (self *Reader) ReadAt(b []byte, off int64) (n int, err error) {
  function NewReaderSize (line 12) | func NewReaderSize(r io.ReadSeeker, size int) *Reader {

FILE: utils/bits/golomb_reader.go
  type GolombBitReader (line 7) | type GolombBitReader struct
    method ReadBit (line 13) | func (self *GolombBitReader) ReadBit() (res uint, err error) {
    method ReadBits (line 25) | func (self *GolombBitReader) ReadBits(n int) (res uint, err error) {
    method ReadExponentialGolombCode (line 36) | func (self *GolombBitReader) ReadExponentialGolombCode() (res uint, er...
    method ReadSE (line 55) | func (self *GolombBitReader) ReadSE() (res uint, err error) {

FILE: utils/bits/pio/reader.go
  function U8 (line 4) | func U8(b []byte) (i uint8) {
  function U16BE (line 8) | func U16BE(b []byte) (i uint16) {
  function I16BE (line 14) | func I16BE(b []byte) (i int16) {
  function I24BE (line 20) | func I24BE(b []byte) (i int32) {
  function U24BE (line 27) | func U24BE(b []byte) (i uint32) {
  function I32BE (line 34) | func I32BE(b []byte) (i int32) {
  function U32LE (line 42) | func U32LE(b []byte) (i uint32) {
  function U32BE (line 50) | func U32BE(b []byte) (i uint32) {
  function U40BE (line 58) | func U40BE(b []byte) (i uint64) {
  function U64BE (line 67) | func U64BE(b []byte) (i uint64) {
  function I64BE (line 79) | func I64BE(b []byte) (i int64) {

FILE: utils/bits/pio/vec.go
  function VecLen (line 3) | func VecLen(vec [][]byte) (n int) {
  function VecSliceTo (line 10) | func VecSliceTo(in [][]byte, out [][]byte, s int, e int) (n int) {
  function VecSlice (line 63) | func VecSlice(in [][]byte, s int, e int) (out [][]byte) {

FILE: utils/bits/pio/vec_test.go
  function ExampleVec (line 8) | func ExampleVec() {

FILE: utils/bits/pio/writer.go
  function PutU8 (line 4) | func PutU8(b []byte, v uint8) {
  function PutI16BE (line 8) | func PutI16BE(b []byte, v int16) {
  function PutU16BE (line 13) | func PutU16BE(b []byte, v uint16) {
  function PutI24BE (line 18) | func PutI24BE(b []byte, v int32) {
  function PutU24BE (line 24) | func PutU24BE(b []byte, v uint32) {
  function PutI32BE (line 30) | func PutI32BE(b []byte, v int32) {
  function PutU32BE (line 37) | func PutU32BE(b []byte, v uint32) {
  function PutU32LE (line 44) | func PutU32LE(b []byte, v uint32) {
  function PutU40BE (line 51) | func PutU40BE(b []byte, v uint64) {
  function PutU48BE (line 59) | func PutU48BE(b []byte, v uint64) {
  function PutU64BE (line 68) | func PutU64BE(b []byte, v uint64) {
  function PutI64BE (line 79) | func PutI64BE(b []byte, v int64) {
Condensed preview — 62 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (432K chars).
[
  {
    "path": "LICENSE",
    "chars": 1057,
    "preview": "MIT License\n\nCopyright (c) 2017 \n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this s"
  },
  {
    "path": "README.md",
    "chars": 2879,
    "preview": "# PLEASE USE joy5 INSTEAD\n\n[joy5](https://github.com/nareix/joy5)\n\n- High performance Copy-on-write gop cache [code](htt"
  },
  {
    "path": "av/av.go",
    "chars": 8254,
    "preview": "\n// Package av defines basic interfaces and data structures of container demux/mux and audio encode/decode.\npackage av\n\n"
  },
  {
    "path": "av/avconv/avconv.go",
    "chars": 4449,
    "preview": "package avconv\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\t\"github.com/nareix/joy4/av/avutil\"\n\t\"github.com/nareix/joy4/av\"\n\t\"github."
  },
  {
    "path": "av/avutil/avutil.go",
    "chars": 6437,
    "preview": "package avutil\n\nimport (\n\t\"io\"\n\t\"strings\"\n\t\"fmt\"\n\t\"bytes\"\n\t\"github.com/nareix/joy4/av\"\n\t\"net/url\"\n\t\"os\"\n\t\"path\"\n)\n\ntype "
  },
  {
    "path": "av/pktque/buf.go",
    "chars": 1319,
    "preview": "package pktque\n\nimport (\n\t\"github.com/nareix/joy4/av\"\n)\n\ntype Buf struct {\n\tHead, Tail BufPos\n\tpkts       []av.Packet\n\tS"
  },
  {
    "path": "av/pktque/filters.go",
    "chars": 4452,
    "preview": "\n// Package pktque provides packet Filter interface and structures used by other components.\npackage pktque\n\nimport (\n\t\""
  },
  {
    "path": "av/pktque/timeline.go",
    "chars": 1095,
    "preview": "package pktque\n\nimport (\n\t\"time\"\n)\n\n/*\npop                                   push\n\n     seg                 seg        s"
  },
  {
    "path": "av/pubsub/queue.go",
    "chars": 4674,
    "preview": "// Packege pubsub implements publisher-subscribers model used in multi-channel streaming.\npackage pubsub\n\nimport (\n\t\"git"
  },
  {
    "path": "av/transcode/transcode.go",
    "chars": 5622,
    "preview": "\n// Package transcoder implements Transcoder based on Muxer/Demuxer and AudioEncoder/AudioDecoder interface.\npackage tra"
  },
  {
    "path": "cgo/ffmpeg/audio.go",
    "chars": 20668,
    "preview": "package ffmpeg\n\n/*\n#include \"ffmpeg.h\"\nint wrap_avcodec_decode_audio4(AVCodecContext *ctx, AVFrame *frame, void *data, i"
  },
  {
    "path": "cgo/ffmpeg/ffmpeg.go",
    "chars": 1383,
    "preview": "package ffmpeg\n\n/*\n#cgo LDFLAGS: -lavformat -lavutil -lavcodec -lavresample -lswscale\n#include \"ffmpeg.h\"\nvoid ffinit() "
  },
  {
    "path": "cgo/ffmpeg/ffmpeg.h",
    "chars": 610,
    "preview": "\n#include <libavformat/avformat.h>\n#include <libavcodec/avcodec.h>\n#include <libavutil/avutil.h>\n#include <libavresample"
  },
  {
    "path": "cgo/ffmpeg/video.go",
    "chars": 2818,
    "preview": "package ffmpeg\n\n/*\n#include \"ffmpeg.h\"\nint wrap_avcodec_decode_video2(AVCodecContext *ctx, AVFrame *frame, void *data, i"
  },
  {
    "path": "codec/aacparser/parser.go",
    "chars": 10742,
    "preview": "package aacparser\n\nimport (\n\t\"github.com/nareix/joy4/utils/bits\"\n\t\"github.com/nareix/joy4/av\"\n\t\"time\"\n\t\"fmt\"\n\t\"bytes\"\n\t\""
  },
  {
    "path": "codec/codec.go",
    "chars": 1254,
    "preview": "package codec\n\nimport (\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/codec/fake\"\n\t\"time\"\n)\n\ntype PCMUCodecData "
  },
  {
    "path": "codec/fake/fake.go",
    "chars": 501,
    "preview": "package fake\n\nimport (\n\t\"github.com/nareix/joy4/av\"\n)\n\ntype CodecData struct {\n\tCodecType_ av.CodecType\n\tSampleRate_ int"
  },
  {
    "path": "codec/h264parser/parser.go",
    "chars": 24446,
    "preview": "\npackage h264parser\n\nimport (\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/utils/bits\"\n\t\"github.com/nareix/joy4"
  },
  {
    "path": "codec/h264parser/parser_test.go",
    "chars": 422,
    "preview": "\npackage h264parser\n\nimport (\n\t\"testing\"\n\t\"encoding/hex\"\n)\n\nfunc TestParser(t *testing.T) {\n\tvar ok bool\n\tvar nalus [][]"
  },
  {
    "path": "doc.go",
    "chars": 333,
    "preview": "\n// Package joy4 is a Golang audio/video library and streaming server.\n// JOY4 is powerful library written in golang, we"
  },
  {
    "path": "examples/audio_decode/main.go",
    "chars": 710,
    "preview": "\npackage main\n\nimport (\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/format\"\n\t\"github.com/nareix/joy4/av/avutil"
  },
  {
    "path": "examples/http_flv_and_rtmp_server/main.go",
    "chars": 2040,
    "preview": "package main\n\nimport (\n\t\"sync\"\n\t\"io\"\n\t\"net/http\"\n\t\"github.com/nareix/joy4/format\"\n\t\"github.com/nareix/joy4/av/avutil\"\n\t\""
  },
  {
    "path": "examples/open_probe_file/main.go",
    "chars": 864,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/av/avutil\"\n\t\"github.com/nareix/joy4/"
  },
  {
    "path": "examples/rtmp_publish/main.go",
    "chars": 629,
    "preview": "package main\n\nimport (\n\t\"github.com/nareix/joy4/av/pktque\"\n\t\"github.com/nareix/joy4/format\"\n\t\"github.com/nareix/joy4/av/"
  },
  {
    "path": "examples/rtmp_server_channels/main.go",
    "chars": 3927,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/av/avutil\"\n\t\"github.com/nareix/joy4/"
  },
  {
    "path": "examples/rtmp_server_proxy/main.go",
    "chars": 599,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"github.com/nareix/joy4/format\"\n\t\"github.com/nareix/joy4/av/avutil\"\n\t\"github.c"
  },
  {
    "path": "examples/rtmp_server_speex_to_aac/main.go",
    "chars": 1169,
    "preview": "package main\n\nimport (\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/av/transcode\"\n\t\"github.com/nareix/joy4/form"
  },
  {
    "path": "examples/transcode/main.go",
    "chars": 968,
    "preview": "package main\n\nimport (\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/av/transcode\"\n\t\"github.com/nareix/joy4/form"
  },
  {
    "path": "format/aac/aac.go",
    "chars": 2705,
    "preview": "\npackage aac\n\nimport (\n\t\"github.com/nareix/joy4/av/avutil\"\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/codec/a"
  },
  {
    "path": "format/flv/flv.go",
    "chars": 10875,
    "preview": "package flv\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"github.com/nareix/joy4/utils/bits/pio\"\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com"
  },
  {
    "path": "format/flv/flvio/amf0.go",
    "chars": 8251,
    "preview": "package flvio\n\nimport (\n\t\"strings\"\n\t\"math\"\n\t\"fmt\"\n\t\"time\"\n\t\"github.com/nareix/joy4/utils/bits/pio\"\n)\n\ntype AMF0ParseErro"
  },
  {
    "path": "format/flv/flvio/flvio.go",
    "chars": 7456,
    "preview": "package flvio\n\nimport (\n\t\"fmt\"\n\t\"github.com/nareix/joy4/utils/bits/pio\"\n\t\"github.com/nareix/joy4/av\"\n\t\"io\"\n\t\"time\"\n)\n\nfu"
  },
  {
    "path": "format/format.go",
    "chars": 558,
    "preview": "package format\n\nimport (\n\t\"github.com/nareix/joy4/format/mp4\"\n\t\"github.com/nareix/joy4/format/ts\"\n\t\"github.com/nareix/jo"
  },
  {
    "path": "format/mp4/demuxer.go",
    "chars": 11681,
    "preview": "package mp4\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/codec/aacpar"
  },
  {
    "path": "format/mp4/handler.go",
    "chars": 556,
    "preview": "package mp4\n\nimport (\n\t\"io\"\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/av/avutil\"\n)\n\nvar CodecTypes = []av.Co"
  },
  {
    "path": "format/mp4/mp4io/atoms.go",
    "chars": 69508,
    "preview": "package mp4io\n\nimport \"github.com/nareix/joy4/utils/bits/pio\"\nimport \"time\"\n\nconst MOOF = Tag(0x6d6f6f66)\n\nfunc (self Mo"
  },
  {
    "path": "format/mp4/mp4io/gen/gen.go",
    "chars": 27764,
    "preview": "\npackage main\n\nimport (\n\t\"strings\"\n\t\"fmt\"\n\t\"os\"\n\t\"go/ast\"\n\t\"go/parser\"\n\t\"go/token\"\n\t\"go/printer\"\n)\n\nfunc getexprs(e ast."
  },
  {
    "path": "format/mp4/mp4io/gen/pattern.go",
    "chars": 7323,
    "preview": "package main\n\nfunc moov_Movie() {\n\tatom(Header, MovieHeader)\n\tatom(MovieExtend, MovieExtend)\n\tatoms(Tracks, Track)\n\t_unk"
  },
  {
    "path": "format/mp4/mp4io/mp4io.go",
    "chars": 10381,
    "preview": "\npackage mp4io\n\nimport (\n\t\"github.com/nareix/joy4/utils/bits/pio\"\n\t\"os\"\n\t\"io\"\n\t\"fmt\"\n\t\"time\"\n\t\"math\"\n\t\"strings\"\n)\n\ntype "
  },
  {
    "path": "format/mp4/muxer.go",
    "chars": 7386,
    "preview": "package mp4\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/codec/aacparser\"\n\t\"github.com"
  },
  {
    "path": "format/mp4/stream.go",
    "chars": 1159,
    "preview": "package mp4\n\nimport (\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/format/mp4/mp4io\"\n\t\"time\"\n)\n\ntype Stream str"
  },
  {
    "path": "format/rtmp/rtmp.go",
    "chars": 37236,
    "preview": "package rtmp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/hmac\"\n\t\"crypto/rand\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"github."
  },
  {
    "path": "format/rtsp/client.go",
    "chars": 28524,
    "preview": "package rtsp\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/md5\"\n\t\"encoding/base64\"\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"gi"
  },
  {
    "path": "format/rtsp/conn.go",
    "chars": 463,
    "preview": "package rtsp\n\nimport (\n\t\"net\"\n\t\"time\"\n)\n\ntype connWithTimeout struct {\n\tTimeout time.Duration\n\tnet.Conn\n}\n\nfunc (self co"
  },
  {
    "path": "format/rtsp/sdp/parser.go",
    "chars": 2753,
    "preview": "package sdp\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"github.com/nareix/joy4/av\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nty"
  },
  {
    "path": "format/rtsp/sdp/parser_test.go",
    "chars": 1090,
    "preview": "package sdp\n\nimport (\n\t\"testing\"\n)\n\nfunc TestParse(t *testing.T) {\n\tinfos := Decode(`\nv=0\no=- 1459325504777324 1 IN IP4 "
  },
  {
    "path": "format/rtsp/stream.go",
    "chars": 399,
    "preview": "package rtsp\n\nimport (\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/format/rtsp/sdp\"\n\t\"time\"\n)\n\ntype Stream str"
  },
  {
    "path": "format/ts/demuxer.go",
    "chars": 6085,
    "preview": "package ts\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"time\"\n\t\"github.com/nareix/joy4/utils/bits/pio\"\n\t\"github.com/nareix/joy4/av\"\n\t\"git"
  },
  {
    "path": "format/ts/handler.go",
    "chars": 408,
    "preview": "package ts\n\nimport (\n\t\"io\"\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/av/avutil\"\n)\n\nfunc Handler(h *avutil.Re"
  },
  {
    "path": "format/ts/muxer.go",
    "chars": 4914,
    "preview": "package ts\n\nimport (\n\t\"fmt\"\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/codec/aacparser\"\n\t\"github.com/nareix/j"
  },
  {
    "path": "format/ts/stream.go",
    "chars": 332,
    "preview": "package ts\n\nimport (\n\t\"time\"\n\t\"github.com/nareix/joy4/av\"\n\t\"github.com/nareix/joy4/format/ts/tsio\"\n)\n\ntype Stream struct"
  },
  {
    "path": "format/ts/tsio/checksum.go",
    "chars": 3313,
    "preview": "package tsio\n\nvar ieeeCrc32Tbl = []uint32{\n\t0x00000000, 0xB71DC104, 0x6E3B8209, 0xD926430D, 0xDC760413, 0x6B6BC517,\n\t0xB"
  },
  {
    "path": "format/ts/tsio/tsio.go",
    "chars": 10902,
    "preview": "\npackage tsio\n\nimport (\n\t\"io\"\n\t\"time\"\n\t\"fmt\"\n\t\"github.com/nareix/joy4/utils/bits/pio\"\n)\n\nconst (\n\tStreamIdH264 = 0xe0\n\tS"
  },
  {
    "path": "utils/bits/bits.go",
    "chars": 2107,
    "preview": "package bits\n\nimport (\n\t\"io\"\n)\n\ntype Reader struct {\n\tR    io.Reader\n\tn    int\n\tbits uint64\n}\n\nfunc (self *Reader) ReadB"
  },
  {
    "path": "utils/bits/bits_test.go",
    "chars": 984,
    "preview": "package bits\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n)\n\nfunc TestBits(t *testing.T) {\n\trdata := []byte{0xf3, 0xb3, 0x45, 0x60}\n\trb"
  },
  {
    "path": "utils/bits/bufio/bufio.go",
    "chars": 326,
    "preview": "package bufio\n\nimport (\n\t\"io\"\n)\n\ntype Reader struct {\n\tbuf [][]byte\n\tR io.ReadSeeker\n}\n\nfunc NewReaderSize(r io.ReadSeek"
  },
  {
    "path": "utils/bits/golomb_reader.go",
    "chars": 1086,
    "preview": "package bits\n\nimport (\n\t\"io\"\n)\n\ntype GolombBitReader struct {\n\tR    io.Reader\n\tbuf  [1]byte\n\tleft byte\n}\n\nfunc (self *Go"
  },
  {
    "path": "utils/bits/pio/pio.go",
    "chars": 48,
    "preview": "\npackage pio\n\nvar RecommendBufioSize = 1024*64\n\n"
  },
  {
    "path": "utils/bits/pio/reader.go",
    "chars": 1612,
    "preview": "\npackage pio\n\nfunc U8(b []byte) (i uint8) {\n\treturn b[0]\n}\n\nfunc U16BE(b []byte) (i uint16) {\n\ti = uint16(b[0])\n\ti <<= 8"
  },
  {
    "path": "utils/bits/pio/vec.go",
    "chars": 974,
    "preview": "package pio\n\nfunc VecLen(vec [][]byte) (n int) {\n\tfor _, b := range vec {\n\t\tn += len(b)\n\t}\n\treturn\n}\n\nfunc VecSliceTo(in"
  },
  {
    "path": "utils/bits/pio/vec_test.go",
    "chars": 304,
    "preview": "\npackage pio\n\nimport (\n\t\"fmt\"\n)\n\nfunc ExampleVec() {\n\tvec := [][]byte{[]byte{1,2,3}, []byte{4,5,6,7,8,9}, []byte{10,11,1"
  },
  {
    "path": "utils/bits/pio/writer.go",
    "chars": 1409,
    "preview": "\npackage pio\n\nfunc PutU8(b []byte, v uint8) {\n\tb[0] = v\n}\n\nfunc PutI16BE(b []byte, v int16) {\n\tb[0] = byte(v>>8)\n\tb[1] ="
  }
]

About this extraction

This page contains the full source code of the nareix/joy4 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 62 files (376.2 KB), approximately 130.3k tokens, and a symbol index with 1164 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!