func (e *Encoder) Connect(h PktHandler) {
	e.d.addHandler(h)
	astiencoder.ConnectNodes(e, h)
}
Connect implements the PktHandlerConnector interface
package astilibav
import (
	"context"
	"errors"
	"fmt"
	"sync/atomic"
	"github.com/asticode/go-astiencoder"
	"github.com/asticode/go-astikit"
	"github.com/asticode/goav/avcodec"
	"github.com/asticode/goav/avformat"
	"github.com/asticode/goav/avutil"
)
var countEncoder uint64
type Encoder struct {
	*astiencoder.BaseNode
	c                  *astikit.Chan
	cl                 *astikit.Closer
	ctxCodec           *avcodec.Context
	d                  *pktDispatcher
	eh                 *astiencoder.EventHandler
	fp                 *framePool
	pp                 *pktPool
	previousDescriptor Descriptor
	statIncomingRate   *astikit.CounterRateStat
	statProcessedRate  *astikit.CounterRateStat
}
type EncoderOptions struct {
	Ctx  Context
	Node astiencoder.NodeOptions
}
func NewEncoder(o EncoderOptions, eh *astiencoder.EventHandler, c *astikit.Closer, s *astiencoder.Stater) (e *Encoder, err error) {
	count := atomic.AddUint64(&countEncoder, uint64(1))
	o.Node.Metadata = o.Node.Metadata.Extend(fmt.Sprintf("encoder_%d", count), fmt.Sprintf("Encoder #%d", count), "Encodes", "encoder")
	e = &Encoder{
		c:                 astikit.NewChan(astikit.ChanOptions{ProcessAll: true}),
		cl:                c.NewChild(),
		eh:                eh,
		statIncomingRate:  astikit.NewCounterRateStat(),
		statProcessedRate: astikit.NewCounterRateStat(),
	}
	e.BaseNode = astiencoder.NewBaseNode(o.Node, eh, s, e, astiencoder.EventTypeToNodeEventName)
	e.fp = newFramePool(e.cl)
	e.pp = newPktPool(e.cl)
	e.d = newPktDispatcher(e, eh, e.pp)
	e.addStats()
	var cdc *avcodec.Codec
	if len(o.Ctx.CodecName) > 0 {
		if cdc = avcodec.AvcodecFindEncoderByName(o.Ctx.CodecName); cdc == nil {
			err = fmt.Errorf("astilibav: no encoder with name %s", o.Ctx.CodecName)
			return
		}
	} else if o.Ctx.CodecID > 0 {
		if cdc = avcodec.AvcodecFindEncoder(o.Ctx.CodecID); cdc == nil {
			err = fmt.Errorf("astilibav: no encoder with id %+v", o.Ctx.CodecID)
			return
		}
	} else {
		err = errors.New("astilibav: neither codec name nor codec id provided")
		return
	}
	if err = o.Ctx.validWithCodec(cdc); err != nil {
		err = fmt.Errorf("astilibav: checking whether the context is valid with the codec failed: %w", err)
		return
	}
	if e.ctxCodec = cdc.AvcodecAllocContext3(); e.ctxCodec == nil {
		err = errors.New("astilibav: no context allocated")
		return
	}
	if o.Ctx.GlobalHeader {
		e.ctxCodec.SetFlags(e.ctxCodec.Flags() | avcodec.AV_CODEC_FLAG_GLOBAL_HEADER)
	}
	if o.Ctx.ThreadCount != nil {
		e.ctxCodec.SetThreadCount(*o.Ctx.ThreadCount)
	}
	switch o.Ctx.CodecType {
	case avutil.AVMEDIA_TYPE_AUDIO:
		e.ctxCodec.SetBitRate(int64(o.Ctx.BitRate))
		e.ctxCodec.SetChannelLayout(o.Ctx.ChannelLayout)
		e.ctxCodec.SetChannels(o.Ctx.Channels)
		e.ctxCodec.SetSampleFmt(o.Ctx.SampleFmt)
		e.ctxCodec.SetSampleRate(o.Ctx.SampleRate)
	case avutil.AVMEDIA_TYPE_VIDEO:
		e.ctxCodec.SetBitRate(int64(o.Ctx.BitRate))
		e.ctxCodec.SetFramerate(o.Ctx.FrameRate)
		e.ctxCodec.SetGopSize(o.Ctx.GopSize)
		e.ctxCodec.SetHeight(o.Ctx.Height)
		e.ctxCodec.SetPixFmt(o.Ctx.PixelFormat)
		e.ctxCodec.SetSampleAspectRatio(o.Ctx.SampleAspectRatio)
		e.ctxCodec.SetTimeBase(o.Ctx.TimeBase)
		e.ctxCodec.SetWidth(o.Ctx.Width)
	default:
		err = fmt.Errorf("astilibav: encoder doesn't handle %v codec type", o.Ctx.CodecType)
		return
	}
	var dict *avutil.Dictionary
	if o.Ctx.Dict != nil {
		if err = o.Ctx.Dict.Parse(&dict); err != nil {
			err = fmt.Errorf("astilibav: parsing dict failed: %w", err)
			return
		}
		defer avutil.AvDictFree(&dict)
	}
	if ret := e.ctxCodec.AvcodecOpen2(cdc, &dict); ret < 0 {
		err = fmt.Errorf("astilibav: d.e.ctxCodec.AvcodecOpen2 failed: %w", NewAvError(ret))
		return
	}
	e.cl.Add(func() error {
		if ret := e.ctxCodec.AvcodecClose(); ret < 0 {
			emitAvError(nil, eh, ret, "d.e.ctxCodec.AvcodecClose failed")
		}
		return nil
	})
	return
}
func (e *Encoder) Close() error {
	return e.cl.Close()
}
func (e *Encoder) addStats() {
	ss := e.c.Stats()
	ss = append(ss, e.d.stats()...)
	ss = append(ss,
		astikit.StatOptions{
			Handler: e.statIncomingRate,
			Metadata: &astikit.StatMetadata{
				Description: "Number of frames coming in per second",
				Label:       "Incoming rate",
				Name:        StatNameIncomingRate,
				Unit:        "fps",
			},
		},
		astikit.StatOptions{
			Handler: e.statProcessedRate,
			Metadata: &astikit.StatMetadata{
				Description: "Number of frames processed per second",
				Label:       "Processed rate",
				Name:        StatNameProcessedRate,
				Unit:        "fps",
			},
		},
	)
	e.BaseNode.AddStats(ss...)
}