live video streaming server in golang
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

120 lines
2.0 KiB

package cache
import (
"errors"
"github.com/gwuhaolin/livego/av"
)
var (
maxGOPCap int = 1024
ErrGopTooBig = errors.New("gop to big")
)
type array struct {
index int
packets []av.Packet
}
func newArray() *array {
ret := &array{
index: 0,
packets: make([]av.Packet, 0, maxGOPCap),
}
return ret
}
func (self *array) reset() {
self.index = 0
self.packets = self.packets[:0]
}
func (self *array) write(packet av.Packet) error {
if self.index >= maxGOPCap {
return ErrGopTooBig
}
self.packets = append(self.packets, packet)
self.index++
return nil
}
func (self *array) send(w av.WriteCloser) error {
var err error
for i := 0; i < self.index; i++ {
packet := self.packets[i]
if err = w.Write(packet); err != nil {
return err
}
}
return err
}
type GopCache struct {
start bool
num int
count int
nextindex int
gops []*array
}
func NewGopCache(num int) *GopCache {
return &GopCache{
count: num,
gops: make([]*array, num),
}
}
func (self *GopCache) writeToArray(chunk av.Packet, startNew bool) error {
var ginc *array
if startNew {
ginc = self.gops[self.nextindex]
if ginc == nil {
ginc = newArray()
self.num++
self.gops[self.nextindex] = ginc
} else {
ginc.reset()
}
self.nextindex = (self.nextindex + 1) % self.count
} else {
ginc = self.gops[(self.nextindex+1)%self.count]
}
ginc.write(chunk)
return nil
}
func (self *GopCache) Write(p av.Packet) {
var ok bool
if p.IsVideo {
vh := p.Header.(av.VideoPacketHeader)
if vh.IsKeyFrame() && !vh.IsSeq() {
ok = true
}
}
if ok || self.start {
self.start = true
self.writeToArray(p, ok)
}
}
func (self *GopCache) sendTo(w av.WriteCloser) error {
var err error
pos := (self.nextindex + 1) % self.count
for i := 0; i < self.num; i++ {
index := (pos - self.num + 1) + i
if index < 0 {
index += self.count
}
g := self.gops[index]
err = g.send(w)
if err != nil {
return err
}
}
return nil
}
func (self *GopCache) Send(w av.WriteCloser) error {
return self.sendTo(w)
}