mirror of https://bitbucket.org/ausocean/av.git
making a time based psi method for when to send packets
Added a case that allows packets to be sent by unit of time (in seconds) rather than by number of packets or nal methods. Also made a variable that can be changed in vidgrinder to choose the amount of time, called PsiTime
This commit is contained in:
parent
c54259b8bd
commit
222864108f
|
@ -155,9 +155,12 @@ type Encoder struct {
|
||||||
|
|
||||||
continuity map[uint16]byte
|
continuity map[uint16]byte
|
||||||
|
|
||||||
nalBasedPSI bool
|
psiMethod int
|
||||||
pktCount int
|
pktCount int
|
||||||
psiSendCount int
|
psiSendCount int
|
||||||
|
psiTime time.Duration
|
||||||
|
temp time.Duration
|
||||||
|
startTime time.Time
|
||||||
mediaPid uint16
|
mediaPid uint16
|
||||||
streamID byte
|
streamID byte
|
||||||
}
|
}
|
||||||
|
@ -167,21 +170,24 @@ type Encoder struct {
|
||||||
func NewEncoder(dst io.WriteCloser, rate float64, mediaType int, options ...func(*Encoder) error) (*Encoder, error) {
|
func NewEncoder(dst io.WriteCloser, rate float64, mediaType int, options ...func(*Encoder) error) (*Encoder, error) {
|
||||||
var mPID uint16
|
var mPID uint16
|
||||||
var sID byte
|
var sID byte
|
||||||
nbp := true
|
psim := timeBased
|
||||||
switch mediaType {
|
switch mediaType {
|
||||||
case EncodeAudio:
|
case EncodeAudio:
|
||||||
mPID = AudioPid
|
mPID = AudioPid
|
||||||
sID = audioStreamID
|
sID = audioStreamID
|
||||||
nbp = false
|
psim = pktBased
|
||||||
case EncodeH265:
|
case EncodeH265:
|
||||||
mPID = VideoPid
|
mPID = VideoPid
|
||||||
sID = H265ID
|
sID = H265ID
|
||||||
|
psim = nalBased
|
||||||
case EncodeH264:
|
case EncodeH264:
|
||||||
mPID = VideoPid
|
mPID = VideoPid
|
||||||
sID = H264ID
|
sID = H264ID
|
||||||
|
psim = nalBased
|
||||||
case EncodeMJPEG:
|
case EncodeMJPEG:
|
||||||
mPID = VideoPid
|
mPID = VideoPid
|
||||||
sID = MJPEGID
|
sID = MJPEGID
|
||||||
|
psim = timeBased
|
||||||
}
|
}
|
||||||
|
|
||||||
pmt := BasePMT
|
pmt := BasePMT
|
||||||
|
@ -202,7 +208,7 @@ func NewEncoder(dst io.WriteCloser, rate float64, mediaType int, options ...func
|
||||||
writePeriod: time.Duration(float64(time.Second) / rate),
|
writePeriod: time.Duration(float64(time.Second) / rate),
|
||||||
ptsOffset: ptsOffset,
|
ptsOffset: ptsOffset,
|
||||||
|
|
||||||
nalBasedPSI: nbp,
|
psiMethod: psim,
|
||||||
|
|
||||||
pktCount: 8,
|
pktCount: 8,
|
||||||
|
|
||||||
|
@ -225,22 +231,47 @@ func NewEncoder(dst io.WriteCloser, rate float64, mediaType int, options ...func
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
pktBased = iota
|
||||||
|
timeBased
|
||||||
|
nalBased
|
||||||
|
)
|
||||||
|
|
||||||
// PacketBasedPSI is an option that can be passed to NewEncoder to select
|
// PacketBasedPSI is an option that can be passed to NewEncoder to select
|
||||||
// packet based PSI writing, i.e. PSI are written to the destination every
|
// packet based PSI writing, i.e. PSI are written to the destination every
|
||||||
// sendCount packets.
|
// sendCount packets.
|
||||||
func PacketBasedPSI(sendCount int) func(*Encoder) error {
|
func PacketBasedPSI(sendCount int) func(*Encoder) error {
|
||||||
return func(e *Encoder) error {
|
return func(e *Encoder) error {
|
||||||
e.nalBasedPSI = false
|
e.psiMethod = pktBased
|
||||||
e.psiSendCount = sendCount
|
e.psiSendCount = sendCount
|
||||||
e.pktCount = e.psiSendCount
|
e.pktCount = e.psiSendCount
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TimeBasedPSI(timeBetweenPSI time.Duration) func(*Encoder) error {
|
||||||
|
return func(e *Encoder) error {
|
||||||
|
e.psiMethod = timeBased
|
||||||
|
e.psiTime = 0
|
||||||
|
e.temp = timeBetweenPSI
|
||||||
|
e.startTime = time.Now()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Write implements io.Writer. Write takes raw video or audio data and encodes into MPEG-TS,
|
// Write implements io.Writer. Write takes raw video or audio data and encodes into MPEG-TS,
|
||||||
// then sending it to the encoder's io.Writer destination.
|
// then sending it to the encoder's io.Writer destination.
|
||||||
func (e *Encoder) Write(data []byte) (int, error) {
|
func (e *Encoder) Write(data []byte) (int, error) {
|
||||||
if e.nalBasedPSI {
|
switch e.psiMethod {
|
||||||
|
case pktBased:
|
||||||
|
if e.pktCount >= e.psiSendCount {
|
||||||
|
e.pktCount = 0
|
||||||
|
err := e.writePSI()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case nalBased:
|
||||||
nalType, err := h264.NALType(data)
|
nalType, err := h264.NALType(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("could not get type from NAL unit, failed with error: %w", err)
|
return 0, fmt.Errorf("could not get type from NAL unit, failed with error: %w", err)
|
||||||
|
@ -252,12 +283,17 @@ func (e *Encoder) Write(data []byte) (int, error) {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if e.pktCount >= e.psiSendCount {
|
case timeBased:
|
||||||
e.pktCount = 0
|
if time.Now().Sub(e.startTime) >= e.psiTime {
|
||||||
err := e.writePSI()
|
e.psiTime = e.temp
|
||||||
if err != nil {
|
e.startTime = time.Now()
|
||||||
return 0, err
|
err := e.writePSI()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare PES data.
|
// Prepare PES data.
|
||||||
|
@ -319,6 +355,7 @@ func (e *Encoder) writePSI() error {
|
||||||
}
|
}
|
||||||
e.pktCount++
|
e.pktCount++
|
||||||
pmtTable, err = updateMeta(pmtTable)
|
pmtTable, err = updateMeta(pmtTable)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ const (
|
||||||
defaultWriteRate = 25
|
defaultWriteRate = 25
|
||||||
defaultClipDuration = 0
|
defaultClipDuration = 0
|
||||||
defaultAudioInputCodec = codecutil.ADPCM
|
defaultAudioInputCodec = codecutil.ADPCM
|
||||||
|
defaultPsiTime = 2
|
||||||
|
|
||||||
// MTS ring buffer defaults.
|
// MTS ring buffer defaults.
|
||||||
defaultMTSRBSize = 100
|
defaultMTSRBSize = 100
|
||||||
|
@ -238,14 +239,16 @@ type Config struct {
|
||||||
Channels int // Number of audio channels, 1 for mono, 2 for stereo.
|
Channels int // Number of audio channels, 1 for mono, 2 for stereo.
|
||||||
BitDepth int // Sample bit depth.
|
BitDepth int // Sample bit depth.
|
||||||
|
|
||||||
RTPAddress string // RTPAddress defines the RTP output destination.
|
RTPAddress string // RTPAddress defines the RTP output destination.
|
||||||
BurstPeriod uint // BurstPeriod defines the revid burst period in seconds.
|
BurstPeriod uint // BurstPeriod defines the revid burst period in seconds.
|
||||||
Rotation uint // Rotation defines the video rotation angle in degrees Raspivid input.
|
Rotation uint // Rotation defines the video rotation angle in degrees Raspivid input.
|
||||||
Height uint // Height defines the input video height Raspivid input.
|
Height uint // Height defines the input video height Raspivid input.
|
||||||
Width uint // Width defines the input video width Raspivid input.
|
Width uint // Width defines the input video width Raspivid input.
|
||||||
Bitrate uint // Bitrate specifies the bitrate for constant bitrate in kbps.
|
Bitrate uint // Bitrate specifies the bitrate for constant bitrate in kbps.
|
||||||
HorizontalFlip bool // HorizontalFlip flips video horizontally for Raspivid input.
|
|
||||||
VerticalFlip bool // VerticalFlip flips video vertically for Raspivid input.
|
HorizontalFlip bool // HorizontalFlip flips video horizontally for Raspivid input.
|
||||||
|
VerticalFlip bool // VerticalFlip flips video vertically for Raspivid input.
|
||||||
|
PsiTime int // Sets the time between a packet being sent
|
||||||
|
|
||||||
// RTMP ring buffer parameters.
|
// RTMP ring buffer parameters.
|
||||||
RTMPRBSize int // The number of elements in the RTMP sender ringbuffer.
|
RTMPRBSize int // The number of elements in the RTMP sender ringbuffer.
|
||||||
|
@ -385,6 +388,11 @@ func (c *Config) Validate() error {
|
||||||
c.MTSRBWriteTimeout = defaultMTSRBWriteTimeout
|
c.MTSRBWriteTimeout = defaultMTSRBWriteTimeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.PsiTime <= 0 {
|
||||||
|
c.Logger.Log(logger.Info, pkg+"PsiTime bad or unset, defaulting", "PsiTime", defaultPsiTime)
|
||||||
|
c.PsiTime = defaultPsiTime
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,10 @@ const (
|
||||||
rtmpConnectionTimeout = 10
|
rtmpConnectionTimeout = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defualtPsiTime = 4
|
||||||
|
)
|
||||||
|
|
||||||
const pkg = "revid: "
|
const pkg = "revid: "
|
||||||
|
|
||||||
type Logger interface {
|
type Logger interface {
|
||||||
|
@ -186,7 +190,7 @@ func (r *Revid) reset(c config.Config) error {
|
||||||
st = mts.EncodeH264
|
st = mts.EncodeH264
|
||||||
case codecutil.MJPEG:
|
case codecutil.MJPEG:
|
||||||
st = mts.EncodeMJPEG
|
st = mts.EncodeMJPEG
|
||||||
encOptions = append(encOptions, mts.PacketBasedPSI(int(r.cfg.MinFrames)))
|
encOptions = append(encOptions, mts.TimeBasedPSI(time.Duration(r.cfg.PsiTime)*time.Second))
|
||||||
default:
|
default:
|
||||||
panic("unknown input codec for raspivid input")
|
panic("unknown input codec for raspivid input")
|
||||||
}
|
}
|
||||||
|
@ -196,7 +200,7 @@ func (r *Revid) reset(c config.Config) error {
|
||||||
st = mts.EncodeH264
|
st = mts.EncodeH264
|
||||||
case codecutil.MJPEG:
|
case codecutil.MJPEG:
|
||||||
st = mts.EncodeMJPEG
|
st = mts.EncodeMJPEG
|
||||||
encOptions = append(encOptions, mts.PacketBasedPSI(int(r.cfg.MinFrames)))
|
encOptions = append(encOptions, mts.TimeBasedPSI(time.Duration(r.cfg.PsiTime)*time.Second))
|
||||||
default:
|
default:
|
||||||
panic("unknown input codec for v4l or input file input")
|
panic("unknown input codec for v4l or input file input")
|
||||||
}
|
}
|
||||||
|
@ -208,7 +212,7 @@ func (r *Revid) reset(c config.Config) error {
|
||||||
st = mts.EncodeH264
|
st = mts.EncodeH264
|
||||||
case codecutil.MJPEG:
|
case codecutil.MJPEG:
|
||||||
st = mts.EncodeMJPEG
|
st = mts.EncodeMJPEG
|
||||||
encOptions = append(encOptions, mts.PacketBasedPSI(int(r.cfg.MinFrames)))
|
encOptions = append(encOptions, mts.TimeBasedPSI(time.Duration(r.cfg.PsiTime)*time.Second))
|
||||||
default:
|
default:
|
||||||
panic("unknown input codec for RTSP input")
|
panic("unknown input codec for RTSP input")
|
||||||
}
|
}
|
||||||
|
@ -611,6 +615,13 @@ func (r *Revid) Update(vars map[string]string) error {
|
||||||
default:
|
default:
|
||||||
r.cfg.Logger.Log(logger.Warning, pkg+"invalid VerticalFlip param", "value", value)
|
r.cfg.Logger.Log(logger.Warning, pkg+"invalid VerticalFlip param", "value", value)
|
||||||
}
|
}
|
||||||
|
case "PsiTime":
|
||||||
|
v, err := strconv.Atoi(value)
|
||||||
|
if err != nil || v < 0 {
|
||||||
|
r.cfg.Logger.Log(logger.Warning, pkg+"invalid PsiTime var", "value", value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
r.cfg.PsiTime = v
|
||||||
case "BurstPeriod":
|
case "BurstPeriod":
|
||||||
v, err := strconv.Atoi(value)
|
v, err := strconv.Atoi(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue