func (d *Decoder) Disconnect(h FrameHandler) {
	d.d.delHandler(h)
	astiencoder.DisconnectNodes(d, h)
}
Disconnect implements the FrameHandlerConnector interface
package astilibav
import (
	"context"
	"fmt"
	"sync/atomic"
	"github.com/asticode/go-astiencoder"
	"github.com/asticode/go-astikit"
	"github.com/asticode/goav/avcodec"
	"github.com/asticode/goav/avutil"
)
var countDecoder uint64
type Decoder struct {
	*astiencoder.BaseNode
	c                 *astikit.Chan
	cl                *astikit.Closer
	ctxCodec          *avcodec.Context
	d                 *frameDispatcher
	eh                *astiencoder.EventHandler
	outputCtx         Context
	fp                *framePool
	pp                *pktPool
	statIncomingRate  *astikit.CounterRateStat
	statProcessedRate *astikit.CounterRateStat
}
type DecoderOptions struct {
	CodecParams *avcodec.CodecParameters
	Node        astiencoder.NodeOptions
	OutputCtx   Context
}
func NewDecoder(o DecoderOptions, eh *astiencoder.EventHandler, c *astikit.Closer, s *astiencoder.Stater) (d *Decoder, err error) {
	count := atomic.AddUint64(&countDecoder, uint64(1))
	o.Node.Metadata = o.Node.Metadata.Extend(fmt.Sprintf("decoder_%d", count), fmt.Sprintf("Decoder #%d", count), "Decodes", "decoder")
	d = &Decoder{
		c:                 astikit.NewChan(astikit.ChanOptions{ProcessAll: true}),
		cl:                c.NewChild(),
		eh:                eh,
		outputCtx:         o.OutputCtx,
		statIncomingRate:  astikit.NewCounterRateStat(),
		statProcessedRate: astikit.NewCounterRateStat(),
	}
	d.BaseNode = astiencoder.NewBaseNode(o.Node, eh, s, d, astiencoder.EventTypeToNodeEventName)
	d.fp = newFramePool(d.cl)
	d.pp = newPktPool(d.cl)
	d.d = newFrameDispatcher(d, eh, d.fp)
	d.addStats()
	var cdc *avcodec.Codec
	if cdc = avcodec.AvcodecFindDecoder(o.CodecParams.CodecId()); cdc == nil {
		err = fmt.Errorf("astilibav: no decoder found for codec id %+v", o.CodecParams.CodecId())
		return
	}
	if d.ctxCodec = cdc.AvcodecAllocContext3(); d.ctxCodec == nil {
		err = fmt.Errorf("astilibav: no context allocated for codec %+v", cdc)
		return
	}
	if ret := avcodec.AvcodecParametersToContext(d.ctxCodec, o.CodecParams); ret < 0 {
		err = fmt.Errorf("astilibav: avcodec.AvcodecParametersToContext failed: %w", NewAvError(ret))
		return
	}
	if ret := d.ctxCodec.AvcodecOpen2(cdc, nil); ret < 0 {
		err = fmt.Errorf("astilibav: d.ctxCodec.AvcodecOpen2 failed: %w", NewAvError(ret))
		return
	}
	d.cl.Add(func() error {
		if ret := d.ctxCodec.AvcodecClose(); ret < 0 {
			emitAvError(nil, eh, ret, "d.ctxCodec.AvcodecClose failed")
		}
		return nil
	})
	return
}
func (d *Decoder) Close() error {
	return d.cl.Close()
}
func (d *Decoder) addStats() {
	ss := d.c.Stats()
	ss = append(ss, d.d.stats()...)
	ss = append(ss,
		astikit.StatOptions{
			Handler: d.statIncomingRate,
			Metadata: &astikit.StatMetadata{
				Description: "Number of packets coming in per second",
				Label:       "Incoming rate",
				Name:        StatNameIncomingRate,
				Unit:        "pps",
			},
		},
		astikit.StatOptions{
			Handler: d.statProcessedRate,
			Metadata: &astikit.StatMetadata{
				Description: "Number of packets processed per second",
				Label:       "Processed rate",
				Name:        StatNameProcessedRate,
				Unit:        "pps",
			},
		},
	)
	d.BaseNode.AddStats(ss...)
}
func (d *Decoder) OutputCtx() Context {
	return d.outputCtx
}
func (d *Decoder) Connect(h FrameHandler) {
	d.d.addHandler(h)
	astiencoder.ConnectNodes(d, h)
}