first commit

This commit is contained in:
Andrey Semochkin
2019-11-30 21:53:21 +01:00
commit 087a2b4c2d
60 changed files with 19091 additions and 0 deletions

73
av/pktque/buf.go Normal file
View File

@@ -0,0 +1,73 @@
package pktque
import (
"github.com/deepch/vdk/av"
)
type Buf struct {
Head, Tail BufPos
pkts []av.Packet
Size int
Count int
}
func NewBuf() *Buf {
return &Buf{
pkts: make([]av.Packet, 64),
}
}
func (self *Buf) Pop() av.Packet {
if self.Count == 0 {
panic("pktque.Buf: Pop() when count == 0")
}
i := int(self.Head) & (len(self.pkts) - 1)
pkt := self.pkts[i]
self.pkts[i] = av.Packet{}
self.Size -= len(pkt.Data)
self.Head++
self.Count--
return pkt
}
func (self *Buf) grow() {
newpkts := make([]av.Packet, len(self.pkts)*2)
for i := self.Head; i.LT(self.Tail); i++ {
newpkts[int(i)&(len(newpkts)-1)] = self.pkts[int(i)&(len(self.pkts)-1)]
}
self.pkts = newpkts
}
func (self *Buf) Push(pkt av.Packet) {
if self.Count == len(self.pkts) {
self.grow()
}
self.pkts[int(self.Tail)&(len(self.pkts)-1)] = pkt
self.Tail++
self.Count++
self.Size += len(pkt.Data)
}
func (self *Buf) Get(pos BufPos) av.Packet {
return self.pkts[int(pos)&(len(self.pkts)-1)]
}
func (self *Buf) IsValidPos(pos BufPos) bool {
return pos.GE(self.Head) && pos.LT(self.Tail)
}
type BufPos int
func (self BufPos) LT(pos BufPos) bool {
return self-pos < 0
}
func (self BufPos) GE(pos BufPos) bool {
return self-pos >= 0
}
func (self BufPos) GT(pos BufPos) bool {
return self-pos > 0
}

190
av/pktque/filters.go Normal file
View File

@@ -0,0 +1,190 @@
// Package pktque provides packet Filter interface and structures used by other components.
package pktque
import (
"time"
"github.com/deepch/vdk/av"
)
type Filter interface {
// Change packet time or drop packet
ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error)
}
// Combine multiple Filters into one, ModifyPacket will be called in order.
type Filters []Filter
func (self Filters) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
for _, filter := range self {
if drop, err = filter.ModifyPacket(pkt, streams, videoidx, audioidx); err != nil {
return
}
if drop {
return
}
}
return
}
// Wrap origin Demuxer and Filter into a new Demuxer, when read this Demuxer filters will be called.
type FilterDemuxer struct {
av.Demuxer
Filter Filter
streams []av.CodecData
videoidx int
audioidx int
}
func (self FilterDemuxer) ReadPacket() (pkt av.Packet, err error) {
if self.streams == nil {
if self.streams, err = self.Demuxer.Streams(); err != nil {
return
}
for i, stream := range self.streams {
if stream.Type().IsVideo() {
self.videoidx = i
} else if stream.Type().IsAudio() {
self.audioidx = i
}
}
}
for {
if pkt, err = self.Demuxer.ReadPacket(); err != nil {
return
}
var drop bool
if drop, err = self.Filter.ModifyPacket(&pkt, self.streams, self.videoidx, self.audioidx); err != nil {
return
}
if !drop {
break
}
}
return
}
// Drop packets until first video key frame arrived.
type WaitKeyFrame struct {
ok bool
}
func (self *WaitKeyFrame) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
if !self.ok && pkt.Idx == int8(videoidx) && pkt.IsKeyFrame {
self.ok = true
}
drop = !self.ok
return
}
// Fix incorrect packet timestamps.
type FixTime struct {
zerobase time.Duration
incrbase time.Duration
lasttime time.Duration
StartFromZero bool // make timestamp start from zero
MakeIncrement bool // force timestamp increment
}
func (self *FixTime) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
if self.StartFromZero {
if self.zerobase == 0 {
self.zerobase = pkt.Time
}
pkt.Time -= self.zerobase
}
if self.MakeIncrement {
pkt.Time -= self.incrbase
if self.lasttime == 0 {
self.lasttime = pkt.Time
}
if pkt.Time < self.lasttime || pkt.Time > self.lasttime+time.Millisecond*500 {
self.incrbase += pkt.Time - self.lasttime
pkt.Time = self.lasttime
}
self.lasttime = pkt.Time
}
return
}
// Drop incorrect packets to make A/V sync.
type AVSync struct {
MaxTimeDiff time.Duration
time []time.Duration
}
func (self *AVSync) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
if self.time == nil {
self.time = make([]time.Duration, len(streams))
if self.MaxTimeDiff == 0 {
self.MaxTimeDiff = time.Millisecond * 500
}
}
start, end, correctable, correcttime := self.check(int(pkt.Idx))
if pkt.Time >= start && pkt.Time < end {
self.time[pkt.Idx] = pkt.Time
} else {
if correctable {
pkt.Time = correcttime
for i := range self.time {
self.time[i] = correcttime
}
} else {
drop = true
}
}
return
}
func (self *AVSync) check(i int) (start time.Duration, end time.Duration, correctable bool, correcttime time.Duration) {
minidx := -1
maxidx := -1
for j := range self.time {
if minidx == -1 || self.time[j] < self.time[minidx] {
minidx = j
}
if maxidx == -1 || self.time[j] > self.time[maxidx] {
maxidx = j
}
}
allthesame := self.time[minidx] == self.time[maxidx]
if i == maxidx {
if allthesame {
correctable = true
} else {
correctable = false
}
} else {
correctable = true
}
start = self.time[minidx]
end = start + self.MaxTimeDiff
correcttime = start + time.Millisecond*40
return
}
// Make packets reading speed as same as walltime, effect like ffmpeg -re option.
type Walltime struct {
firsttime time.Time
}
func (self *Walltime) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
if pkt.Idx == 0 {
if self.firsttime.IsZero() {
self.firsttime = time.Now()
}
pkttime := self.firsttime.Add(pkt.Time)
delta := pkttime.Sub(time.Now())
if delta > 0 {
time.Sleep(delta)
}
}
return
}

61
av/pktque/timeline.go Normal file
View File

@@ -0,0 +1,61 @@
package pktque
import (
"time"
)
/*
pop push
seg seg seg
|--------| |---------| |---|
20ms 40ms 5ms
----------------- time -------------------->
headtm tailtm
*/
type tlSeg struct {
tm, dur time.Duration
}
type Timeline struct {
segs []tlSeg
headtm time.Duration
}
func (self *Timeline) Push(tm time.Duration, dur time.Duration) {
if len(self.segs) > 0 {
tail := self.segs[len(self.segs)-1]
diff := tm-(tail.tm+tail.dur)
if diff < 0 {
tm -= diff
}
}
self.segs = append(self.segs, tlSeg{tm, dur})
}
func (self *Timeline) Pop(dur time.Duration) (tm time.Duration) {
if len(self.segs) == 0 {
return self.headtm
}
tm = self.segs[0].tm
for dur > 0 && len(self.segs) > 0 {
seg := &self.segs[0]
sub := dur
if seg.dur < sub {
sub = seg.dur
}
seg.dur -= sub
dur -= sub
seg.tm += sub
self.headtm += sub
if seg.dur == 0 {
copy(self.segs[0:], self.segs[1:])
self.segs = self.segs[:len(self.segs)-1]
}
}
return
}