mirror of
https://github.com/Monibuca/engine.git
synced 2025-10-06 00:56:58 +08:00
修复DTS生成时遇到PTS超过循环的情况
This commit is contained in:
@@ -25,24 +25,28 @@ func (d *DTSEstimator) Clone() *DTSEstimator {
|
|||||||
|
|
||||||
func (d *DTSEstimator) add(pts uint32) {
|
func (d *DTSEstimator) add(pts uint32) {
|
||||||
i := 0
|
i := 0
|
||||||
if len(d.cache) >= 4 {
|
l := len(d.cache)
|
||||||
i = len(d.cache) - 3
|
if l >= 4 {
|
||||||
|
l--
|
||||||
|
// i = l - 3
|
||||||
|
d.cache = append(d.cache[:0], d.cache[1:]...)[:l]
|
||||||
}
|
}
|
||||||
|
|
||||||
var new_cache []uint32
|
for ; i < l; i = i + 1 {
|
||||||
for ; i < len(d.cache); i = i + 1 {
|
|
||||||
if d.cache[i] > pts {
|
if d.cache[i] > pts {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
new_cache = append(new_cache, d.cache[i])
|
|
||||||
}
|
}
|
||||||
new_cache = append(new_cache, pts)
|
d.cache = append(d.cache, pts)
|
||||||
new_cache = append(new_cache, d.cache[i:]...)
|
d.cache = append(d.cache[:i+1], d.cache[i:l]...)
|
||||||
d.cache = new_cache
|
d.cache[i] = pts
|
||||||
}
|
}
|
||||||
|
|
||||||
// Feed provides PTS to the estimator, and returns the estimated DTS.
|
// Feed provides PTS to the estimator, and returns the estimated DTS.
|
||||||
func (d *DTSEstimator) Feed(pts uint32) uint32 {
|
func (d *DTSEstimator) Feed(pts uint32) uint32 {
|
||||||
|
if pts < d.prevPTS && d.prevPTS-pts > 0x80000000 {
|
||||||
|
*d = *NewDTSEstimator()
|
||||||
|
}
|
||||||
d.add(pts)
|
d.add(pts)
|
||||||
dts := pts
|
dts := pts
|
||||||
if !d.hasB {
|
if !d.hasB {
|
||||||
|
17
common/dtsestimator_test.go
Normal file
17
common/dtsestimator_test.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDts(t *testing.T) {
|
||||||
|
t.Run(t.Name(), func(t *testing.T) {
|
||||||
|
dtsg := NewDTSEstimator()
|
||||||
|
var pts uint32 = 0xFFFFFFFF - 5
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
dts := dtsg.Feed(pts)
|
||||||
|
pts++
|
||||||
|
t.Logf("dts=%d", dts)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@@ -88,11 +88,6 @@ func (av *AVFrame) Reset() {
|
|||||||
av.DeltaTime = 0
|
av.DeltaTime = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
type SequenceHead struct {
|
|
||||||
AVCC []byte
|
|
||||||
Seq int //收到第几个序列帧,用于变码率时让订阅者发送序列帧
|
|
||||||
}
|
|
||||||
|
|
||||||
type ParamaterSets [][]byte
|
type ParamaterSets [][]byte
|
||||||
|
|
||||||
func (v ParamaterSets) GetAnnexB() (r net.Buffers) {
|
func (v ParamaterSets) GetAnnexB() (r net.Buffers) {
|
||||||
|
@@ -286,8 +286,8 @@ func (opt *Plugin) Pull(streamPath string, url string, puller IPuller, save int)
|
|||||||
time.Sleep(time.Second * 5)
|
time.Sleep(time.Second * 5)
|
||||||
} else {
|
} else {
|
||||||
if err = opt.Publish(streamPath, puller); err != nil {
|
if err = opt.Publish(streamPath, puller); err != nil {
|
||||||
if puber := Streams.Get(streamPath).Publisher; puber != puller && puber != nil {
|
if stream := Streams.Get(streamPath); stream != nil && stream.Publisher != puller && stream.Publisher != nil {
|
||||||
io := puber.GetPublisher()
|
io := stream.Publisher.GetPublisher()
|
||||||
opt.Error("puller is not publisher", zap.String("ID", io.ID), zap.String("Type", io.Type), zap.Error(err))
|
opt.Error("puller is not publisher", zap.String("ID", io.ID), zap.String("Type", io.Type), zap.Error(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@@ -39,8 +39,7 @@ func (vt *H264) WriteSliceBytes(slice []byte) {
|
|||||||
vt.ParamaterSets[1] = slice
|
vt.ParamaterSets[1] = slice
|
||||||
lenSPS := len(vt.Video.SPS)
|
lenSPS := len(vt.Video.SPS)
|
||||||
lenPPS := len(vt.Video.PPS)
|
lenPPS := len(vt.Video.PPS)
|
||||||
b := util.Buffer(vt.SequenceHead)
|
var b util.Buffer
|
||||||
b.Reset()
|
|
||||||
if lenSPS > 3 {
|
if lenSPS > 3 {
|
||||||
b.Write(codec.RTMP_AVC_HEAD[:6])
|
b.Write(codec.RTMP_AVC_HEAD[:6])
|
||||||
b.Write(vt.Video.SPS[1:4])
|
b.Write(vt.Video.SPS[1:4])
|
||||||
@@ -51,8 +50,10 @@ func (vt *H264) WriteSliceBytes(slice []byte) {
|
|||||||
b.WriteByte(0xE1)
|
b.WriteByte(0xE1)
|
||||||
b.WriteUint16(uint16(lenSPS))
|
b.WriteUint16(uint16(lenSPS))
|
||||||
b.Write(vt.Video.SPS)
|
b.Write(vt.Video.SPS)
|
||||||
|
b.WriteByte(0x01)
|
||||||
b.WriteUint16(uint16(lenPPS))
|
b.WriteUint16(uint16(lenPPS))
|
||||||
b.Write(vt.Video.PPS)
|
b.Write(vt.Video.PPS)
|
||||||
|
vt.SequenceHead = b
|
||||||
vt.updateSequeceHead()
|
vt.updateSequeceHead()
|
||||||
case codec.NALU_IDR_Picture:
|
case codec.NALU_IDR_Picture:
|
||||||
vt.Value.IFrame = true
|
vt.Value.IFrame = true
|
||||||
@@ -119,7 +120,7 @@ func (vt *H264) WriteRTPFrame(frame *RTPFrame) {
|
|||||||
if util.Bit1(frame.Payload[1], 0) {
|
if util.Bit1(frame.Payload[1], 0) {
|
||||||
vt.WriteSliceByte(naluType.Parse(frame.Payload[1]).Or(frame.Payload[0] & 0x60))
|
vt.WriteSliceByte(naluType.Parse(frame.Payload[1]).Or(frame.Payload[0] & 0x60))
|
||||||
}
|
}
|
||||||
rv.AUList.Push(vt.BytesPool.GetShell(frame.Payload[naluType.Offset():]))
|
rv.AUList.Pre.Value.Push(vt.BytesPool.GetShell(frame.Payload[naluType.Offset():]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
frame.SequenceNumber += vt.rtpSequence //增加偏移,需要增加rtp包后需要顺延
|
frame.SequenceNumber += vt.rtpSequence //增加偏移,需要增加rtp包后需要顺延
|
||||||
|
@@ -111,12 +111,7 @@ func (vt *H265) WriteRTPFrame(frame *RTPFrame) {
|
|||||||
if naluType := fuHeader & 0b00111111; util.Bit1(fuHeader, 0) {
|
if naluType := fuHeader & 0b00111111; util.Bit1(fuHeader, 0) {
|
||||||
vt.WriteSliceByte(first3[0]&0b10000001|(naluType<<1), first3[1])
|
vt.WriteSliceByte(first3[0]&0b10000001|(naluType<<1), first3[1])
|
||||||
}
|
}
|
||||||
rv.AUList.Push(vt.BytesPool.GetShell(buffer))
|
rv.AUList.Pre.Value.Push(vt.BytesPool.GetShell(buffer))
|
||||||
// if util.Bit1(fuHeader, 1) {
|
|
||||||
// complete := rv.Raw[lastIndex] //拼接完成
|
|
||||||
// rv.Raw = rv.Raw[:lastIndex] // 缩短一个元素,因为后面的方法会加回去
|
|
||||||
// vt.WriteSlice(complete)
|
|
||||||
// }
|
|
||||||
default:
|
default:
|
||||||
vt.WriteSliceBytes(frame.Payload)
|
vt.WriteSliceBytes(frame.Payload)
|
||||||
}
|
}
|
||||||
|
@@ -179,12 +179,12 @@ func (vt *Video) CompleteAVCC(rv *AVFrame) {
|
|||||||
// 写入CTS
|
// 写入CTS
|
||||||
util.PutBE(b[2:5], (rv.PTS-rv.DTS)/90)
|
util.PutBE(b[2:5], (rv.PTS-rv.DTS)/90)
|
||||||
rv.AVCC.Push(mem)
|
rv.AVCC.Push(mem)
|
||||||
vt.Value.AUList.Range(func(au *util.BLL) bool {
|
rv.AUList.Range(func(au *util.BLL) bool {
|
||||||
mem = vt.BytesPool.Get(4)
|
mem = vt.BytesPool.Get(4)
|
||||||
util.PutBE(mem.Value, uint32(au.ByteLength))
|
util.PutBE(mem.Value, uint32(au.ByteLength))
|
||||||
vt.Value.AVCC.Push(mem)
|
rv.AVCC.Push(mem)
|
||||||
au.Range(func(slice util.BLI) bool {
|
au.Range(func(slice util.BLI) bool {
|
||||||
vt.Value.AVCC.Push(vt.BytesPool.GetShell(slice))
|
rv.AVCC.Push(vt.BytesPool.GetShell(slice))
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
return true
|
return true
|
||||||
|
@@ -83,7 +83,7 @@ type AMF struct {
|
|||||||
Buffer
|
Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadAMF[T any](amf *AMF) (result T) {
|
func ReadAMF[T string | float64 | bool | map[string]any](amf *AMF) (result T) {
|
||||||
value, err := amf.Unmarshal()
|
value, err := amf.Unmarshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@@ -82,7 +82,7 @@ func (p *List[T]) Range(do func(value T) bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *List[T]) Recycle() {
|
func (p *List[T]) Recycle() {
|
||||||
for item := p.Next; item != nil && !item.IsRoot(); {
|
for item := p.Next; item != nil && item.list != nil && !item.IsRoot(); {
|
||||||
next := item.Next
|
next := item.Next
|
||||||
item.Recycle()
|
item.Recycle()
|
||||||
item = next
|
item = next
|
||||||
|
16
util/pool.go
16
util/pool.go
@@ -78,7 +78,7 @@ func (r *BLLsReader) CanRead() bool {
|
|||||||
return r.ListItem != nil && !r.IsRoot()
|
return r.ListItem != nil && !r.IsRoot()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *BLLsReader) ReadByte() (b byte, err error) {
|
func (r *BLLsReader) ReadByte() (b byte, err error) {
|
||||||
if r.BLLReader.CanRead() {
|
if r.BLLReader.CanRead() {
|
||||||
b, err = r.BLLReader.ReadByte()
|
b, err = r.BLLReader.ReadByte()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -92,6 +92,7 @@ func (r *BLLsReader) ReadByte() (b byte, err error) {
|
|||||||
r.BLLReader = *r.Value.NewReader()
|
r.BLLReader = *r.Value.NewReader()
|
||||||
return r.BLLReader.ReadByte()
|
return r.BLLReader.ReadByte()
|
||||||
}
|
}
|
||||||
|
|
||||||
type BLLs struct {
|
type BLLs struct {
|
||||||
List[*BLL]
|
List[*BLL]
|
||||||
ByteLength int
|
ByteLength int
|
||||||
@@ -257,6 +258,9 @@ type BytesPool []List[BLI]
|
|||||||
|
|
||||||
// 获取来自真实内存的切片的——假内存块,即只回收外壳
|
// 获取来自真实内存的切片的——假内存块,即只回收外壳
|
||||||
func (p BytesPool) GetShell(b []byte) (item *ListItem[BLI]) {
|
func (p BytesPool) GetShell(b []byte) (item *ListItem[BLI]) {
|
||||||
|
if len(p) == 0 {
|
||||||
|
return &ListItem[BLI]{Value: b}
|
||||||
|
}
|
||||||
if p[0].Length > 0 {
|
if p[0].Length > 0 {
|
||||||
item = p[0].Shift()
|
item = p[0].Shift()
|
||||||
} else {
|
} else {
|
||||||
@@ -275,17 +279,19 @@ func (p BytesPool) Get(size int) (item *ListItem[BLI]) {
|
|||||||
item = p[i].Shift()
|
item = p[i].Shift()
|
||||||
item.Value = item.Value[:size]
|
item.Value = item.Value[:size]
|
||||||
} else {
|
} else {
|
||||||
item = &ListItem[BLI]{}
|
item = &ListItem[BLI]{
|
||||||
|
Value: make([]byte, size, level),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
item.Pool = &p[i]
|
item.Pool = &p[i]
|
||||||
item.Value = make([]byte, size, level)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Pool 中没有就无法回收
|
// Pool 中没有就无法回收
|
||||||
if item == nil {
|
if item == nil {
|
||||||
item = &ListItem[BLI]{}
|
item = &ListItem[BLI]{
|
||||||
item.Value = make([]byte, size)
|
Value: make([]byte, size),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user