mirror of https://github.com/gwuhaolin/livego.git
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
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) |
|
}
|
|
|