mirror of https://bitbucket.org/ausocean/av.git
Merged in timebasedpsi (pull request #306)
making a time based psi method for when to send packets Approved-by: Saxon Milton <saxon.milton@gmail.com>
This commit is contained in:
commit
a16d37f19e
|
@ -155,9 +155,12 @@ type Encoder struct {
|
|||
|
||||
continuity map[uint16]byte
|
||||
|
||||
nalBasedPSI bool
|
||||
psiMethod int
|
||||
pktCount int
|
||||
psiSendCount int
|
||||
psiTime time.Duration
|
||||
psiSetTime time.Duration
|
||||
startTime time.Time
|
||||
mediaPid uint16
|
||||
streamID byte
|
||||
}
|
||||
|
@ -167,21 +170,24 @@ type Encoder struct {
|
|||
func NewEncoder(dst io.WriteCloser, rate float64, mediaType int, options ...func(*Encoder) error) (*Encoder, error) {
|
||||
var mPID uint16
|
||||
var sID byte
|
||||
nbp := true
|
||||
psiM := timeBased
|
||||
switch mediaType {
|
||||
case EncodeAudio:
|
||||
mPID = AudioPid
|
||||
sID = audioStreamID
|
||||
nbp = false
|
||||
psiM = pktBased
|
||||
case EncodeH265:
|
||||
mPID = VideoPid
|
||||
sID = H265ID
|
||||
psiM = nalBased
|
||||
case EncodeH264:
|
||||
mPID = VideoPid
|
||||
sID = H264ID
|
||||
psiM = nalBased
|
||||
case EncodeMJPEG:
|
||||
mPID = VideoPid
|
||||
sID = MJPEGID
|
||||
psiM = timeBased
|
||||
}
|
||||
|
||||
pmt := BasePMT
|
||||
|
@ -202,7 +208,7 @@ func NewEncoder(dst io.WriteCloser, rate float64, mediaType int, options ...func
|
|||
writePeriod: time.Duration(float64(time.Second) / rate),
|
||||
ptsOffset: ptsOffset,
|
||||
|
||||
nalBasedPSI: nbp,
|
||||
psiMethod: psiM,
|
||||
|
||||
pktCount: 8,
|
||||
|
||||
|
@ -225,22 +231,52 @@ func NewEncoder(dst io.WriteCloser, rate float64, mediaType int, options ...func
|
|||
return e, nil
|
||||
}
|
||||
|
||||
// These three constants are used to select between the three different
|
||||
// methods of when the PSI is sent.
|
||||
const (
|
||||
pktBased = iota
|
||||
timeBased
|
||||
nalBased
|
||||
)
|
||||
|
||||
// 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
|
||||
// sendCount packets.
|
||||
func PacketBasedPSI(sendCount int) func(*Encoder) error {
|
||||
return func(e *Encoder) error {
|
||||
e.nalBasedPSI = false
|
||||
e.psiMethod = pktBased
|
||||
e.psiSendCount = sendCount
|
||||
e.pktCount = e.psiSendCount
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// TimeBasedPSI is another option that can be passed to NewEncoder to select
|
||||
// time based PSI writing, i.e. PSI are written to the destination every dur (duration)
|
||||
// (defualt is 2 seconds).
|
||||
func TimeBasedPSI(dur time.Duration) func(*Encoder) error {
|
||||
return func(e *Encoder) error {
|
||||
e.psiMethod = timeBased
|
||||
e.psiTime = 0
|
||||
e.psiSetTime = dur
|
||||
e.startTime = time.Now()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
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)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("could not get type from NAL unit, failed with error: %w", err)
|
||||
|
@ -252,12 +288,18 @@ func (e *Encoder) Write(data []byte) (int, error) {
|
|||
return 0, err
|
||||
}
|
||||
}
|
||||
} else if e.pktCount >= e.psiSendCount {
|
||||
e.pktCount = 0
|
||||
case timeBased:
|
||||
if time.Now().Sub(e.startTime) >= e.psiTime {
|
||||
e.psiTime = e.psiSetTime
|
||||
e.startTime = time.Now()
|
||||
err := e.writePSI()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
}
|
||||
default:
|
||||
panic("Undefined PSI method")
|
||||
}
|
||||
|
||||
// Prepare PES data.
|
||||
|
@ -319,6 +361,7 @@ func (e *Encoder) writePSI() error {
|
|||
}
|
||||
e.pktCount++
|
||||
pmtTable, err = updateMeta(pmtTable)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ const (
|
|||
defaultWriteRate = 25
|
||||
defaultClipDuration = 0
|
||||
defaultAudioInputCodec = codecutil.ADPCM
|
||||
defaultPSITime = 2
|
||||
|
||||
// MTS ring buffer defaults.
|
||||
defaultMTSRBSize = 100
|
||||
|
@ -244,8 +245,10 @@ type Config struct {
|
|||
Height uint // Height defines the input video height Raspivid input.
|
||||
Width uint // Width defines the input video width Raspivid input.
|
||||
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.
|
||||
PSITime int // Sets the time between a packet being sent
|
||||
|
||||
// RTMP ring buffer parameters.
|
||||
RTMPRBSize int // The number of elements in the RTMP sender ringbuffer.
|
||||
|
@ -424,6 +427,11 @@ func (c *Config) Validate() error {
|
|||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -186,7 +186,7 @@ func (r *Revid) reset(c config.Config) error {
|
|||
st = mts.EncodeH264
|
||||
case codecutil.MJPEG:
|
||||
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:
|
||||
panic("unknown input codec for raspivid input")
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ func (r *Revid) reset(c config.Config) error {
|
|||
st = mts.EncodeH264
|
||||
case codecutil.MJPEG:
|
||||
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:
|
||||
panic("unknown input codec for v4l or input file input")
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ func (r *Revid) reset(c config.Config) error {
|
|||
st = mts.EncodeH264
|
||||
case codecutil.MJPEG:
|
||||
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:
|
||||
panic("unknown input codec for RTSP input")
|
||||
}
|
||||
|
@ -611,6 +611,13 @@ func (r *Revid) Update(vars map[string]string) error {
|
|||
default:
|
||||
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":
|
||||
v, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in New Issue