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:
Ella Pietraroia 2019-12-17 10:21:56 +10:30
parent c54259b8bd
commit 222864108f
3 changed files with 78 additions and 22 deletions

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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 {