Compare commits
53 Commits
renovate/g
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
0e65c9d1cc | ||
|
bcb44378a5 | ||
|
dc22c36964 | ||
|
7bb8737cc8 | ||
|
5438b5fbf7 | ||
|
2979d3f55d | ||
|
3c1eaad780 | ||
|
b6b1f4a437 | ||
|
f6346a05aa | ||
|
413b746b2f | ||
|
c6f36a9a89 | ||
|
230b6c6ad1 | ||
|
fd7ecfeaad | ||
|
4b060bc442 | ||
|
9f075c6682 | ||
|
0e06666006 | ||
|
b84c19f719 | ||
|
7a563b07e3 | ||
|
a743575ac9 | ||
|
e4035e4407 | ||
|
4df258b899 | ||
|
385d9cc93c | ||
|
06a7f70701 | ||
|
975d994507 | ||
|
eaab841cfb | ||
|
9d21d056dd | ||
|
5a989a5c40 | ||
|
0b08aa7224 | ||
|
9e244f72bf | ||
|
8d4be0821c | ||
|
8958197548 | ||
|
def88cb695 | ||
|
175afae1c1 | ||
|
c923e0010b | ||
|
cc3f215a23 | ||
|
f567925cf9 | ||
|
472775f07c | ||
|
b31edccea5 | ||
|
a027ba9c94 | ||
|
57a79ff9e2 | ||
|
8679fe28f1 | ||
|
e8d8603d2c | ||
|
61aa8e4f72 | ||
|
030575e585 | ||
|
24c185b51e | ||
|
31d128e853 | ||
|
37a9a8619c | ||
|
417f833371 | ||
|
b2320900f5 | ||
|
898c5e5d57 | ||
|
4db7d612fc | ||
|
2be4196875 | ||
|
7d87dbe2dd |
3
av/av.go
3
av/av.go
@ -121,6 +121,7 @@ var (
|
||||
VP8 = MakeVideoCodecType(avCodecTypeMagic + 4)
|
||||
VP9 = MakeVideoCodecType(avCodecTypeMagic + 5)
|
||||
AV1 = MakeVideoCodecType(avCodecTypeMagic + 6)
|
||||
MJPEG = MakeVideoCodecType(avCodecTypeMagic + 7)
|
||||
AAC = MakeAudioCodecType(avCodecTypeMagic + 1)
|
||||
PCM_MULAW = MakeAudioCodecType(avCodecTypeMagic + 2)
|
||||
PCM_ALAW = MakeAudioCodecType(avCodecTypeMagic + 3)
|
||||
@ -254,6 +255,8 @@ type Packet struct {
|
||||
Time time.Duration // packet decode time
|
||||
Duration time.Duration //packet duration
|
||||
Data []byte // packet data
|
||||
Extension bool
|
||||
Extensions []byte
|
||||
}
|
||||
|
||||
// Raw audio frame.
|
||||
|
@ -5,10 +5,10 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/av/avutil"
|
||||
"github.com/deepch/vdk/av/pktque"
|
||||
"github.com/deepch/vdk/av/transcode"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av/avutil"
|
||||
"git.r-2.top/kunmeng/vdk/av/pktque"
|
||||
"git.r-2.top/kunmeng/vdk/av/transcode"
|
||||
)
|
||||
|
||||
var Debug bool
|
||||
|
@ -9,7 +9,9 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
)
|
||||
|
||||
type HandlerDemuxer struct {
|
||||
@ -310,3 +312,31 @@ func CopyFile(dst av.Muxer, src av.Demuxer) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Equal(c1 []av.CodecData, c2 []av.CodecData) bool {
|
||||
if len(c1) != len(c2) {
|
||||
return false
|
||||
}
|
||||
for i, codec := range c1 {
|
||||
if codec.Type() != c2[i].Type() {
|
||||
return false
|
||||
}
|
||||
switch codec.Type() {
|
||||
case av.H264:
|
||||
if eq := bytes.Compare(
|
||||
codec.(h264parser.CodecData).AVCDecoderConfRecordBytes(),
|
||||
c2[i].(h264parser.CodecData).AVCDecoderConfRecordBytes(),
|
||||
); eq != 0 {
|
||||
return false
|
||||
}
|
||||
case av.AAC:
|
||||
if eq := bytes.Compare(
|
||||
codec.(aacparser.CodecData).MPEG4AudioConfigBytes(),
|
||||
c2[i].(aacparser.CodecData).MPEG4AudioConfigBytes(),
|
||||
); eq != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package pktque
|
||||
|
||||
import (
|
||||
"github.com/deepch/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
)
|
||||
|
||||
type Buf struct {
|
||||
|
@ -4,7 +4,7 @@ package pktque
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
)
|
||||
|
||||
type Filter interface {
|
||||
@ -36,7 +36,7 @@ type FilterDemuxer struct {
|
||||
audioidx int
|
||||
}
|
||||
|
||||
func (self FilterDemuxer) ReadPacket() (pkt av.Packet, err error) {
|
||||
func (self *FilterDemuxer) ReadPacket() (pkt av.Packet, err error) {
|
||||
if self.streams == nil {
|
||||
if self.streams, err = self.Demuxer.Streams(); err != nil {
|
||||
return
|
||||
@ -170,6 +170,20 @@ func (self *AVSync) check(i int) (start time.Duration, end time.Duration, correc
|
||||
return
|
||||
}
|
||||
|
||||
type CalcDuration struct {
|
||||
LastTime map[int8]time.Duration
|
||||
}
|
||||
|
||||
func (self *CalcDuration) ModifyPacket(pkt *av.Packet, streams []av.CodecData, videoidx int, audioidx int) (drop bool, err error) {
|
||||
if tmp, ok := self.LastTime[pkt.Idx]; ok && tmp != 0 {
|
||||
pkt.Duration = pkt.Time - self.LastTime[pkt.Idx]
|
||||
} else if pkt.Time < 100*time.Millisecond {
|
||||
pkt.Duration = pkt.Time
|
||||
}
|
||||
self.LastTime[pkt.Idx] = pkt.Time
|
||||
return
|
||||
}
|
||||
|
||||
// Make packets reading speed as same as walltime, effect like ffmpeg -re option.
|
||||
type Walltime struct {
|
||||
firsttime time.Time
|
||||
|
@ -6,8 +6,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/av/pktque"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av/pktque"
|
||||
)
|
||||
|
||||
// time
|
||||
|
@ -5,8 +5,8 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/av/pktque"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av/pktque"
|
||||
)
|
||||
|
||||
var Debug bool
|
||||
|
@ -17,9 +17,9 @@ import (
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/av/avutil"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av/avutil"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
)
|
||||
|
||||
const debug = false
|
||||
|
@ -20,8 +20,8 @@ import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
)
|
||||
|
||||
type VideoDecoder struct {
|
||||
|
@ -6,8 +6,8 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/utils/bits"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits"
|
||||
)
|
||||
|
||||
// copied from libavcodec/mpeg4audio.h
|
||||
|
@ -3,8 +3,8 @@ package codec
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/fake"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/fake"
|
||||
)
|
||||
|
||||
type OpusCodecData struct {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package fake
|
||||
|
||||
import (
|
||||
"github.com/deepch/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
)
|
||||
|
||||
type CodecData struct {
|
||||
|
@ -5,10 +5,11 @@ import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/utils/bits"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"time"
|
||||
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -664,13 +665,21 @@ func (self CodecData) AVCDecoderConfRecordBytes() []byte {
|
||||
}
|
||||
|
||||
func (self CodecData) SPS() []byte {
|
||||
if len(self.RecordInfo.SPS) > 0 {
|
||||
return self.RecordInfo.SPS[0]
|
||||
}
|
||||
|
||||
return []byte{0}
|
||||
}
|
||||
|
||||
func (self CodecData) PPS() []byte {
|
||||
if len(self.RecordInfo.PPS) > 0 {
|
||||
return self.RecordInfo.PPS[0]
|
||||
}
|
||||
|
||||
return []byte{0}
|
||||
}
|
||||
|
||||
func (self CodecData) Width() int {
|
||||
return int(self.SPSInfo.Width)
|
||||
}
|
||||
|
@ -4,10 +4,11 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/utils/bits"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"time"
|
||||
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
type SPSInfo struct {
|
||||
@ -462,7 +463,8 @@ func (self CodecData) Resolution() string {
|
||||
}
|
||||
|
||||
func (self CodecData) Tag() string {
|
||||
return fmt.Sprintf("hvc1.%02X%02X%02X", self.RecordInfo.AVCProfileIndication, self.RecordInfo.ProfileCompatibility, self.RecordInfo.AVCLevelIndication)
|
||||
//return fmt.Sprintf("hvc1.%02X%02X%02X", self.RecordInfo.AVCProfileIndication, self.RecordInfo.ProfileCompatibility, self.RecordInfo.AVCLevelIndication)
|
||||
return "hev1.1.6.L120.90"
|
||||
}
|
||||
|
||||
func (self CodecData) Bandwidth() string {
|
||||
@ -529,7 +531,7 @@ type AVCDecoderConfRecord struct {
|
||||
var ErrDecconfInvalid = fmt.Errorf("h265parser: AVCDecoderConfRecord invalid")
|
||||
|
||||
func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) {
|
||||
if len(b) < 7 {
|
||||
if len(b) < 30 {
|
||||
err = ErrDecconfInvalid
|
||||
return
|
||||
}
|
||||
@ -537,8 +539,36 @@ func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) {
|
||||
self.ProfileCompatibility = b[2]
|
||||
self.AVCLevelIndication = b[3]
|
||||
self.LengthSizeMinusOne = b[4] & 0x03
|
||||
spscount := int(b[5] & 0x1f)
|
||||
n += 6
|
||||
|
||||
vpscount := int(b[25] & 0x1f)
|
||||
n += 26
|
||||
for i := 0; i < vpscount; i++ {
|
||||
if len(b) < n+2 {
|
||||
err = ErrDecconfInvalid
|
||||
return
|
||||
}
|
||||
vpslen := int(pio.U16BE(b[n:]))
|
||||
n += 2
|
||||
|
||||
if len(b) < n+vpslen {
|
||||
err = ErrDecconfInvalid
|
||||
return
|
||||
}
|
||||
self.VPS = append(self.VPS, b[n:n+vpslen])
|
||||
n += vpslen
|
||||
}
|
||||
|
||||
if len(b) < n+1 {
|
||||
err = ErrDecconfInvalid
|
||||
return
|
||||
}
|
||||
|
||||
n++
|
||||
n++
|
||||
|
||||
spscount := int(b[n])
|
||||
n++
|
||||
|
||||
for i := 0; i < spscount; i++ {
|
||||
if len(b) < n+2 {
|
||||
err = ErrDecconfInvalid
|
||||
@ -555,10 +585,8 @@ func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) {
|
||||
n += spslen
|
||||
}
|
||||
|
||||
if len(b) < n+1 {
|
||||
err = ErrDecconfInvalid
|
||||
return
|
||||
}
|
||||
n++
|
||||
n++
|
||||
|
||||
ppscount := int(b[n])
|
||||
n++
|
||||
@ -578,25 +606,6 @@ func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) {
|
||||
self.PPS = append(self.PPS, b[n:n+ppslen])
|
||||
n += ppslen
|
||||
}
|
||||
|
||||
vpscount := int(b[n])
|
||||
n++
|
||||
|
||||
for i := 0; i < vpscount; i++ {
|
||||
if len(b) < n+2 {
|
||||
err = ErrDecconfInvalid
|
||||
return
|
||||
}
|
||||
vpslen := int(pio.U16BE(b[n:]))
|
||||
n += 2
|
||||
|
||||
if len(b) < n+vpslen {
|
||||
err = ErrDecconfInvalid
|
||||
return
|
||||
}
|
||||
self.VPS = append(self.VPS, b[n:n+vpslen])
|
||||
n += vpslen
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
10
codec/mjpeg/parser.go
Normal file
10
codec/mjpeg/parser.go
Normal file
@ -0,0 +1,10 @@
|
||||
package mjpeg
|
||||
|
||||
import "git.r-2.top/kunmeng/vdk/av"
|
||||
|
||||
type CodecData struct {
|
||||
}
|
||||
|
||||
func (d CodecData) Type() av.CodecType {
|
||||
return av.MJPEG
|
||||
}
|
@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
)
|
||||
|
||||
type CodecData struct {
|
||||
|
25
example/test/main.go
Normal file
25
example/test/main.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.r-2.top/kunmeng/vdk/format/ts"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f, _ := os.Open("edb9708f29b24ba9b175808d6b9df9c6541e25766d4a40209a8f903948b72f3f.ts")
|
||||
m := ts.NewDemuxer(f)
|
||||
var i int
|
||||
for {
|
||||
p, err := m.ReadPacket()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if p.IsKeyFrame {
|
||||
i = 0
|
||||
}
|
||||
log.Println(i, p.Time, p.Data[4:10], len(p.Data))
|
||||
i++
|
||||
|
||||
}
|
||||
}
|
71
example/transcoder/main.go
Normal file
71
example/transcoder/main.go
Normal file
@ -0,0 +1,71 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"git.r-2.top/kunmeng/vdk/format/rtspv2"
|
||||
"git.r-2.top/kunmeng/vdk/format/ts"
|
||||
"log"
|
||||
"os/exec"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
RTSPClient, err := rtspv2.Dial(rtspv2.RTSPClientOptions{URL: "rtsp://192.168.211.210:8554", DisableAudio: true, DialTimeout: 3 * time.Second, ReadWriteTimeout: 5 * time.Second, Debug: false, OutgoingProxy: false})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(ctx, "ffmpeg", "-flags", "low_delay", "-analyzeduration", "1", "-fflags", "-nobuffer", "-probesize", "1024k", "-f", "mpegts", "-i", "-", "-vcodec", "libx264", "-preset", "ultrafast", "-bf", "0", "-f", "mpegts", "-max_muxing_queue_size", "400", "-pes_payload_size", "0", "pipe:1")
|
||||
inPipe, _ := cmd.StdinPipe()
|
||||
outPipe, _ := cmd.StdoutPipe()
|
||||
//cmd.Stderr = os.Stderr
|
||||
mux := ts.NewMuxer(inPipe)
|
||||
demuxer := ts.NewDemuxer(outPipe)
|
||||
codec := RTSPClient.CodecData
|
||||
mux.WriteHeader(codec)
|
||||
go func() {
|
||||
imNewCodec, err := demuxer.Streams()
|
||||
log.Println("new codec data", imNewCodec, err)
|
||||
//for i, data := range imNewCodec {
|
||||
// log.Println(i, data)
|
||||
//}
|
||||
for {
|
||||
demuxer.ReadPacket()
|
||||
//pkt, err := demuxer.ReadPacket()
|
||||
//if err != nil {
|
||||
// log.Panic(err)
|
||||
//}
|
||||
//log.Println("im new pkt ===>", pkt.Idx, pkt.Time)
|
||||
}
|
||||
}()
|
||||
cmd.Start()
|
||||
var start bool
|
||||
for {
|
||||
select {
|
||||
case signals := <-RTSPClient.Signals:
|
||||
switch signals {
|
||||
case rtspv2.SignalCodecUpdate:
|
||||
//?
|
||||
case rtspv2.SignalStreamRTPStop:
|
||||
return
|
||||
}
|
||||
case packetAV := <-RTSPClient.OutgoingPacketQueue:
|
||||
//log.Println(packetAV.Extensions)
|
||||
t := time.UnixMilli(int64(binary.LittleEndian.Uint32(packetAV.Extensions[20:24]))*1000 + int64(binary.LittleEndian.Uint32(packetAV.Extensions[24:28]))/1000)
|
||||
log.Println(t.Format("2006-01-02 15:04:05.000"))
|
||||
//println(binary.LittleEndian.Uint32(packetAV.Extensions[24:28]))
|
||||
//println(binary.LittleEndian.Uint32(packetAV.Extensions[20:24]))
|
||||
if packetAV.IsKeyFrame {
|
||||
start = true
|
||||
}
|
||||
if !start {
|
||||
continue
|
||||
}
|
||||
if err = mux.WritePacket(*packetAV); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,9 +6,9 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/av/avutil"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av/avutil"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
)
|
||||
|
||||
type Muxer struct {
|
||||
|
@ -12,9 +12,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -5,14 +5,15 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/av/avutil"
|
||||
"github.com/deepch/vdk/codec"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/codec/fake"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/format/flv/flvio"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av/avutil"
|
||||
"git.r-2.top/kunmeng/vdk/codec"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/fake"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h265parser"
|
||||
"git.r-2.top/kunmeng/vdk/format/flv/flvio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
var MaxProbePacketCount = 20
|
||||
@ -28,6 +29,8 @@ func NewMetadataByStreams(streams []av.CodecData) (metadata flvio.AMFMap, err er
|
||||
switch typ {
|
||||
case av.H264:
|
||||
metadata["videocodecid"] = flvio.VIDEO_H264
|
||||
case av.H265:
|
||||
metadata["videocodecid"] = flvio.VIDEO_H265
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("flv: metadata: unsupported video codecType=%v", stream.Type())
|
||||
@ -87,11 +90,13 @@ func (self *Prober) PushTag(tag flvio.Tag, timestamp int32) (err error) {
|
||||
switch tag.AVCPacketType {
|
||||
case flvio.AVC_SEQHDR:
|
||||
if !self.GotVideo {
|
||||
var stream h264parser.CodecData
|
||||
var stream av.CodecData
|
||||
if stream, err = h264parser.NewCodecDataFromAVCDecoderConfRecord(tag.Data); err != nil {
|
||||
if stream, err = h265parser.NewCodecDataFromAVCDecoderConfRecord(tag.Data); err != nil {
|
||||
err = fmt.Errorf("flv: h264 seqhdr invalid")
|
||||
return
|
||||
}
|
||||
}
|
||||
self.VideoStreamIdx = len(self.Streams)
|
||||
self.Streams = append(self.Streams, stream)
|
||||
self.GotVideo = true
|
||||
@ -222,7 +227,17 @@ func CodecDataToTag(stream av.CodecData) (_tag flvio.Tag, ok bool, err error) {
|
||||
}
|
||||
ok = true
|
||||
_tag = tag
|
||||
|
||||
case av.H265:
|
||||
h265c := stream.(h265parser.CodecData)
|
||||
tag := flvio.Tag{
|
||||
Type: flvio.TAG_VIDEO,
|
||||
AVCPacketType: flvio.AVC_SEQHDR,
|
||||
CodecID: flvio.VIDEO_H265,
|
||||
Data: h265c.AVCDecoderConfRecordBytes(),
|
||||
FrameType: flvio.FRAME_KEY,
|
||||
}
|
||||
ok = true
|
||||
_tag = tag
|
||||
case av.NELLYMOSER:
|
||||
case av.SPEEX:
|
||||
|
||||
@ -272,7 +287,19 @@ func PacketToTag(pkt av.Packet, stream av.CodecData) (tag flvio.Tag, timestamp i
|
||||
} else {
|
||||
tag.FrameType = flvio.FRAME_INTER
|
||||
}
|
||||
|
||||
case av.H265:
|
||||
tag = flvio.Tag{
|
||||
Type: flvio.TAG_VIDEO,
|
||||
AVCPacketType: flvio.AVC_NALU,
|
||||
CodecID: flvio.VIDEO_H265,
|
||||
Data: pkt.Data,
|
||||
CompositionTime: flvio.TimeToTs(pkt.CompositionTime),
|
||||
}
|
||||
if pkt.IsKeyFrame {
|
||||
tag.FrameType = flvio.FRAME_KEY
|
||||
} else {
|
||||
tag.FrameType = flvio.FRAME_INTER
|
||||
}
|
||||
case av.AAC:
|
||||
tag = flvio.Tag{
|
||||
Type: flvio.TAG_AUDIO,
|
||||
@ -336,7 +363,7 @@ func NewMuxer(w io.Writer) *Muxer {
|
||||
return NewMuxerWriteFlusher(bufio.NewWriterSize(w, pio.RecommendBufioSize))
|
||||
}
|
||||
|
||||
var CodecTypes = []av.CodecType{av.H264, av.AAC, av.SPEEX}
|
||||
var CodecTypes = []av.CodecType{av.H264, av.AAC, av.SPEEX, av.H265}
|
||||
|
||||
func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) {
|
||||
var flags uint8
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
type AMF0ParseError struct {
|
||||
|
@ -5,8 +5,8 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
func TsToTime(ts int32) time.Duration {
|
||||
@ -59,6 +59,7 @@ const (
|
||||
FRAME_INTER = 2
|
||||
|
||||
VIDEO_H264 = 7
|
||||
VIDEO_H265 = 12
|
||||
)
|
||||
|
||||
type Tag struct {
|
||||
|
@ -4,9 +4,9 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
type DecoderConfigDescriptor struct {
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
type StreamDescriptor struct {
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
type Tag uint32
|
||||
|
@ -1,6 +1,6 @@
|
||||
package fmp4io
|
||||
|
||||
import "github.com/deepch/vdk/utils/bits/pio"
|
||||
import "git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
|
||||
const AVC1 = Tag(0x61766331)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package fmp4io
|
||||
|
||||
import "github.com/deepch/vdk/utils/bits/pio"
|
||||
import "git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
|
||||
const MVEX = Tag(0x6d766578)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package fmp4io
|
||||
|
||||
import "github.com/deepch/vdk/utils/bits/pio"
|
||||
import "git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
|
||||
const FTYP = Tag(0x66747970)
|
||||
|
||||
|
@ -3,7 +3,7 @@ package fmp4io
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
const MOOF = Tag(0x6d6f6f66)
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
func GetTime32(b []byte) (t time.Time) {
|
||||
|
@ -3,7 +3,7 @@ package fmp4io
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
const MDIA = Tag(0x6d646961)
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
const MOOV = Tag(0x6d6f6f76)
|
||||
|
@ -1,8 +1,8 @@
|
||||
package fmp4io
|
||||
|
||||
import (
|
||||
"github.com/deepch/vdk/format/fmp4/esio"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/format/fmp4/esio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
const MP4A = Tag(0x6d703461)
|
||||
|
@ -1,7 +1,7 @@
|
||||
package fmp4io
|
||||
|
||||
import (
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -3,7 +3,7 @@ package fmp4io
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
const DREF = Tag(0x64726566)
|
||||
|
@ -3,7 +3,7 @@ package fmp4io
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
const STBL = Tag(0x7374626c)
|
||||
|
@ -1,6 +1,6 @@
|
||||
package fmp4io
|
||||
|
||||
import "github.com/deepch/vdk/utils/bits/pio"
|
||||
import "git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
|
||||
const SIDX = Tag(0x73696478)
|
||||
|
||||
|
@ -3,7 +3,7 @@ package fragment
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
)
|
||||
|
||||
type Fragment struct {
|
||||
|
@ -6,9 +6,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/format/fmp4/fmp4io"
|
||||
"github.com/deepch/vdk/format/fmp4/fragment"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/format/fmp4/fmp4io"
|
||||
"git.r-2.top/kunmeng/vdk/format/fmp4/fragment"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -1,11 +1,11 @@
|
||||
package fmp4
|
||||
|
||||
import (
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/format/fmp4/fmp4io"
|
||||
"github.com/deepch/vdk/format/fmp4/fragment"
|
||||
"github.com/deepch/vdk/format/fmp4/timescale"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/format/fmp4/fmp4io"
|
||||
"git.r-2.top/kunmeng/vdk/format/fmp4/fragment"
|
||||
"git.r-2.top/kunmeng/vdk/format/fmp4/timescale"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
type fragmentWithData struct {
|
||||
|
@ -3,12 +3,12 @@ package fmp4
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/codec/opusparser"
|
||||
"github.com/deepch/vdk/format/fmp4/esio"
|
||||
"github.com/deepch/vdk/format/fmp4/fmp4io"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/opusparser"
|
||||
"git.r-2.top/kunmeng/vdk/format/fmp4/esio"
|
||||
"git.r-2.top/kunmeng/vdk/format/fmp4/fmp4io"
|
||||
)
|
||||
|
||||
// Track creates a TRAK atom for this stream
|
||||
|
@ -3,10 +3,10 @@ package fmp4
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/format/fmp4/fmp4io"
|
||||
"github.com/deepch/vdk/format/fmp4/fragment"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/format/fmp4/fmp4io"
|
||||
"git.r-2.top/kunmeng/vdk/format/fmp4/fragment"
|
||||
)
|
||||
|
||||
// TrackFragmenter writes a single audio or video stream as a series of CMAF (fMP4) fragments
|
||||
|
@ -1,13 +1,13 @@
|
||||
package format
|
||||
|
||||
import (
|
||||
"github.com/deepch/vdk/av/avutil"
|
||||
"github.com/deepch/vdk/format/aac"
|
||||
"github.com/deepch/vdk/format/flv"
|
||||
"github.com/deepch/vdk/format/mp4"
|
||||
"github.com/deepch/vdk/format/rtmp"
|
||||
"github.com/deepch/vdk/format/rtsp"
|
||||
"github.com/deepch/vdk/format/ts"
|
||||
"git.r-2.top/kunmeng/vdk/av/avutil"
|
||||
"git.r-2.top/kunmeng/vdk/format/aac"
|
||||
"git.r-2.top/kunmeng/vdk/format/flv"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4"
|
||||
"git.r-2.top/kunmeng/vdk/format/rtmp"
|
||||
"git.r-2.top/kunmeng/vdk/format/rtsp"
|
||||
"git.r-2.top/kunmeng/vdk/format/ts"
|
||||
)
|
||||
|
||||
func RegisterAll() {
|
||||
|
@ -6,9 +6,9 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/format/mkv/mkvio"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/format/mkv/mkvio"
|
||||
)
|
||||
|
||||
type Demuxer struct {
|
||||
|
@ -3,8 +3,8 @@ package mkv
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/av/avutil"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av/avutil"
|
||||
)
|
||||
|
||||
var CodecTypes = []av.CodecType{av.H264, av.AAC}
|
||||
|
@ -3,7 +3,7 @@ package mkv
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
)
|
||||
|
||||
type Stream struct {
|
||||
|
@ -6,10 +6,10 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/format/mp4/mp4io"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
|
||||
)
|
||||
|
||||
type Demuxer struct {
|
||||
|
@ -3,8 +3,8 @@ package mp4
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/av/avutil"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av/avutil"
|
||||
)
|
||||
|
||||
var CodecTypes = []av.CodecType{av.H264, av.AAC}
|
||||
|
@ -1,9 +1,10 @@
|
||||
package mp4io
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
const MOOF = Tag(0x6d6f6f66)
|
||||
@ -32,6 +33,7 @@ func (self HV1Desc) Tag() Tag {
|
||||
}
|
||||
|
||||
// const HVC1 = Tag(0x68766331)
|
||||
//
|
||||
// func (self HVC1Desc) Tag() Tag {
|
||||
// return HVC1
|
||||
// }
|
||||
@ -304,6 +306,10 @@ func (self *Movie) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("trak", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Tracks) > 100 {
|
||||
err = errors.New("too many tracks")
|
||||
return
|
||||
}
|
||||
self.Tracks = append(self.Tracks, atom)
|
||||
}
|
||||
default:
|
||||
@ -313,6 +319,10 @@ func (self *Movie) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -601,6 +611,10 @@ func (self *Track) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -940,6 +954,10 @@ func (self *Media) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -1173,6 +1191,10 @@ func (self *MediaInfo) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -1255,6 +1277,10 @@ func (self *DataInfo) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -1817,6 +1843,10 @@ func (self *SampleDesc) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -1982,6 +2012,10 @@ func (self *MP4ADesc) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -2291,6 +2325,10 @@ func (self *AVC1Desc) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -2411,6 +2449,10 @@ func (self *HV1Desc) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -2954,6 +2996,10 @@ func (self *MovieFrag) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("traf", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Tracks) > 100 {
|
||||
err = errors.New("too many tracks")
|
||||
return
|
||||
}
|
||||
self.Tracks = append(self.Tracks, atom)
|
||||
}
|
||||
default:
|
||||
@ -2963,6 +3009,10 @@ func (self *MovieFrag) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -3127,6 +3177,10 @@ func (self *TrackFrag) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -3197,6 +3251,10 @@ func (self *MovieExtend) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("trex", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Tracks) > 100 {
|
||||
err = errors.New("too many tracks")
|
||||
return
|
||||
}
|
||||
self.Tracks = append(self.Tracks, atom)
|
||||
}
|
||||
default:
|
||||
@ -3206,6 +3264,10 @@ func (self *MovieExtend) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
|
@ -966,7 +966,7 @@ func genatoms(filename, outfilename string) {
|
||||
&ast.GenDecl{
|
||||
Tok: token.IMPORT,
|
||||
Specs: []ast.Spec{
|
||||
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/deepch/vdk/utils/bits/pio"`}},
|
||||
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"git.r-2.top/kunmeng/vdk/utils/bits/pio"`}},
|
||||
},
|
||||
},
|
||||
&ast.GenDecl{
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
type ParseError struct {
|
||||
@ -387,6 +387,10 @@ func ReadFileAtoms(r io.ReadSeeker) (atoms []Atom, err error) {
|
||||
return
|
||||
}
|
||||
size := pio.U32BE(taghdr[0:])
|
||||
if size > 5242880 {
|
||||
err = parseErr("len", 5242880, err)
|
||||
return
|
||||
}
|
||||
tag := Tag(pio.U32BE(taghdr[4:]))
|
||||
|
||||
var atom Atom
|
||||
|
@ -3,14 +3,14 @@ package mp4
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h265parser"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/format/mp4/mp4io"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
type Muxer struct {
|
||||
@ -18,6 +18,7 @@ type Muxer struct {
|
||||
bufw *bufio.Writer
|
||||
wpos int64
|
||||
streams []*Stream
|
||||
NegativeTsMakeZero bool
|
||||
}
|
||||
|
||||
func NewMuxer(w io.WriteSeeker) *Muxer {
|
||||
@ -120,7 +121,7 @@ func (self *Stream) fillTrackAtom() (err error) {
|
||||
self.trackAtom.Header.TrackWidth = float64(width)
|
||||
self.trackAtom.Header.TrackHeight = float64(height)
|
||||
} else if self.Type() == av.H265 {
|
||||
codec := self.CodecData.(h264parser.CodecData)
|
||||
codec := self.CodecData.(h265parser.CodecData)
|
||||
width, height := codec.Width(), codec.Height()
|
||||
self.sample.SampleDesc.HV1Desc = &mp4io.HV1Desc{
|
||||
DataRefIdx: 1,
|
||||
@ -204,9 +205,13 @@ func (self *Muxer) WritePacket(pkt av.Packet) (err error) {
|
||||
|
||||
func (self *Stream) writePacket(pkt av.Packet, rawdur time.Duration) (err error) {
|
||||
if rawdur < 0 {
|
||||
if self.muxer.NegativeTsMakeZero {
|
||||
rawdur = 0
|
||||
} else {
|
||||
err = fmt.Errorf("mp4: stream#%d time=%v < lasttime=%v", pkt.Idx, pkt.Time, self.lastpkt.Time)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = self.muxer.bufw.Write(pkt.Data); err != nil {
|
||||
return
|
||||
|
@ -3,8 +3,8 @@ package mp4
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/format/mp4/mp4io"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
|
||||
)
|
||||
|
||||
type Stream struct {
|
||||
|
@ -1,6 +1,6 @@
|
||||
package mp4f
|
||||
|
||||
import "github.com/deepch/vdk/format/mp4/mp4io"
|
||||
import "git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
|
||||
|
||||
type FDummy struct {
|
||||
Data []byte
|
||||
|
@ -1,8 +1,8 @@
|
||||
package mp4fio
|
||||
|
||||
import (
|
||||
"github.com/deepch/vdk/format/mp4/mp4io"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
func (self MovieFrag) Tag() mp4io.Tag {
|
||||
|
@ -966,7 +966,7 @@ func genatoms(filename, outfilename string) {
|
||||
&ast.GenDecl{
|
||||
Tok: token.IMPORT,
|
||||
Specs: []ast.Spec{
|
||||
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/deepch/vdk/utils/bits/pio"`}},
|
||||
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"git.r-2.top/kunmeng/vdk/utils/bits/pio"`}},
|
||||
},
|
||||
},
|
||||
&ast.GenDecl{
|
||||
|
@ -1,8 +1,8 @@
|
||||
package mp4fio
|
||||
|
||||
import (
|
||||
"github.com/deepch/vdk/format/mp4/mp4io"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
type ElemStreamDesc struct {
|
||||
|
@ -3,17 +3,18 @@ package mp4f
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/codec/h265parser"
|
||||
"github.com/deepch/vdk/format/fmp4/fmp4io"
|
||||
"github.com/deepch/vdk/format/mp4/mp4io"
|
||||
"github.com/deepch/vdk/format/mp4f/mp4fio"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h265parser"
|
||||
"git.r-2.top/kunmeng/vdk/format/fmp4/fmp4io"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4f/mp4fio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
type Muxer struct {
|
||||
@ -202,7 +203,8 @@ func (self *Stream) fillTrackAtom() (err error) {
|
||||
self.trackAtom.Media.Info.Video = &mp4io.VideoMediaInfo{
|
||||
Flags: 0x000001,
|
||||
}
|
||||
self.codecString = fmt.Sprintf("hvc1.%02X%02X%02X", codec.RecordInfo.AVCProfileIndication, codec.RecordInfo.ProfileCompatibility, codec.RecordInfo.AVCLevelIndication)
|
||||
//self.codecString = fmt.Sprintf("hvc1.%02X%02X%02X", codec.RecordInfo.AVCProfileIndication, codec.RecordInfo.ProfileCompatibility, codec.RecordInfo.AVCLevelIndication)
|
||||
self.codecString = "hev1.1.6.L120.90"
|
||||
|
||||
} else if self.Type() == av.AAC {
|
||||
codec := self.CodecData.(aacparser.CodecData)
|
||||
@ -237,14 +239,15 @@ func (self *Muxer) WriteTrailer() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (element *Muxer) WriteHeader(streams []av.CodecData) (err error) {
|
||||
func (element *Muxer) WriteHeader(streams []av.CodecData) error {
|
||||
element.streams = []*Stream{}
|
||||
for _, stream := range streams {
|
||||
if err = element.newStream(stream); err != nil {
|
||||
return
|
||||
if err := element.newStream(stream); err != nil {
|
||||
log.Println("WriteHeader", err)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (element *Muxer) GetInit(streams []av.CodecData) (string, []byte) {
|
||||
@ -284,6 +287,9 @@ func (element *Muxer) GetInit(streams []av.CodecData) (string, []byte) {
|
||||
}
|
||||
|
||||
func (element *Muxer) WritePacket(pkt av.Packet, GOP bool) (bool, []byte, error) {
|
||||
if pkt.Idx+1 > int8(len(element.streams)) {
|
||||
return false, nil, nil
|
||||
}
|
||||
stream := element.streams[pkt.Idx]
|
||||
if GOP {
|
||||
ts := time.Duration(0)
|
||||
|
@ -3,10 +3,10 @@ package mp4f
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/format/mp4"
|
||||
"github.com/deepch/vdk/format/mp4/mp4io"
|
||||
"github.com/deepch/vdk/format/mp4f/mp4fio"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4f/mp4fio"
|
||||
)
|
||||
|
||||
type Stream struct {
|
||||
|
@ -6,10 +6,10 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/format/mp4/mp4io"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
|
||||
)
|
||||
|
||||
type Demuxer struct {
|
||||
|
@ -3,8 +3,8 @@ package mp4
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/av/avutil"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av/avutil"
|
||||
)
|
||||
|
||||
var CodecTypes = []av.CodecType{av.H264, av.AAC}
|
||||
|
@ -1,9 +1,10 @@
|
||||
package mp4io
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
const MOOF = Tag(0x6d6f6f66)
|
||||
@ -32,6 +33,7 @@ func (self HV1Desc) Tag() Tag {
|
||||
}
|
||||
|
||||
// const HVC1 = Tag(0x68766331)
|
||||
//
|
||||
// func (self HVC1Desc) Tag() Tag {
|
||||
// return HVC1
|
||||
// }
|
||||
@ -304,6 +306,10 @@ func (self *Movie) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("trak", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Tracks) > 100 {
|
||||
err = errors.New("too many tracks")
|
||||
return
|
||||
}
|
||||
self.Tracks = append(self.Tracks, atom)
|
||||
}
|
||||
default:
|
||||
@ -313,6 +319,10 @@ func (self *Movie) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -601,6 +611,10 @@ func (self *Track) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -940,6 +954,10 @@ func (self *Media) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -1173,6 +1191,10 @@ func (self *MediaInfo) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -1255,6 +1277,10 @@ func (self *DataInfo) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -1817,6 +1843,10 @@ func (self *SampleDesc) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -1982,6 +2012,10 @@ func (self *MP4ADesc) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -2291,6 +2325,10 @@ func (self *AVC1Desc) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -2411,6 +2449,10 @@ func (self *HV1Desc) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -2954,6 +2996,10 @@ func (self *MovieFrag) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("traf", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Tracks) > 100 {
|
||||
err = errors.New("too many tracks")
|
||||
return
|
||||
}
|
||||
self.Tracks = append(self.Tracks, atom)
|
||||
}
|
||||
default:
|
||||
@ -2963,6 +3009,10 @@ func (self *MovieFrag) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -3127,6 +3177,10 @@ func (self *TrackFrag) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
@ -3197,6 +3251,10 @@ func (self *MovieExtend) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("trex", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Tracks) > 100 {
|
||||
err = errors.New("too many tracks")
|
||||
return
|
||||
}
|
||||
self.Tracks = append(self.Tracks, atom)
|
||||
}
|
||||
default:
|
||||
@ -3206,6 +3264,10 @@ func (self *MovieExtend) Unmarshal(b []byte, offset int) (n int, err error) {
|
||||
err = parseErr("", n+offset, err)
|
||||
return
|
||||
}
|
||||
if len(self.Unknowns) > 100 {
|
||||
err = errors.New("too many unknowns")
|
||||
return
|
||||
}
|
||||
self.Unknowns = append(self.Unknowns, atom)
|
||||
}
|
||||
}
|
||||
|
@ -966,7 +966,7 @@ func genatoms(filename, outfilename string) {
|
||||
&ast.GenDecl{
|
||||
Tok: token.IMPORT,
|
||||
Specs: []ast.Spec{
|
||||
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/deepch/vdk/utils/bits/pio"`}},
|
||||
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"git.r-2.top/kunmeng/vdk/utils/bits/pio"`}},
|
||||
},
|
||||
},
|
||||
&ast.GenDecl{
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
type ParseError struct {
|
||||
@ -387,6 +387,12 @@ func ReadFileAtoms(r io.ReadSeeker) (atoms []Atom, err error) {
|
||||
return
|
||||
}
|
||||
size := pio.U32BE(taghdr[0:])
|
||||
|
||||
if size == 0 {
|
||||
err = fmt.Errorf("bad hdr size")
|
||||
return
|
||||
}
|
||||
|
||||
tag := Tag(pio.U32BE(taghdr[4:]))
|
||||
|
||||
var atom Atom
|
||||
|
@ -6,11 +6,11 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/format/mp4/mp4io"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
type Muxer struct {
|
||||
@ -18,6 +18,7 @@ type Muxer struct {
|
||||
bufw *bufio.Writer
|
||||
wpos int64
|
||||
streams []*Stream
|
||||
NegativeTsMakeZero bool
|
||||
}
|
||||
|
||||
func NewMuxer(w io.WriteSeeker) *Muxer {
|
||||
@ -181,9 +182,13 @@ func (self *Muxer) WritePacket(pkt av.Packet) (err error) {
|
||||
|
||||
func (self *Stream) writePacket(pkt av.Packet, rawdur time.Duration) (err error) {
|
||||
if rawdur < 0 {
|
||||
if self.muxer.NegativeTsMakeZero {
|
||||
rawdur = 0
|
||||
} else {
|
||||
err = fmt.Errorf("mp4: stream#%d time=%v < lasttime=%v", pkt.Idx, pkt.Time, self.lastpkt.Time)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = self.muxer.bufw.Write(pkt.Data); err != nil {
|
||||
return
|
||||
|
@ -3,8 +3,8 @@ package mp4
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/format/mp4/mp4io"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
|
||||
)
|
||||
|
||||
type Stream struct {
|
||||
|
77
format/mse/muxer.go
Normal file
77
format/mse/muxer.go
Normal file
@ -0,0 +1,77 @@
|
||||
package mse
|
||||
|
||||
import (
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4f"
|
||||
"github.com/gobwas/ws"
|
||||
"github.com/gobwas/ws/wsutil"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var Debug bool
|
||||
|
||||
type Muxer struct {
|
||||
m *mp4f.Muxer
|
||||
r *http.Request
|
||||
w http.ResponseWriter
|
||||
conn net.Conn
|
||||
}
|
||||
|
||||
func NewMuxer(r *http.Request, w http.ResponseWriter) (*Muxer, error) {
|
||||
conn, _, _, err := ws.UpgradeHTTP(r, w)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go func() {
|
||||
defer func() {
|
||||
conn.Close()
|
||||
}()
|
||||
for {
|
||||
if _, _, err = wsutil.NextReader(conn, ws.StateServerSide); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return &Muxer{
|
||||
conn: conn,
|
||||
m: mp4f.NewMuxer(nil),
|
||||
r: r,
|
||||
w: w,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Muxer) WriteHeader(streams []av.CodecData) (err error) {
|
||||
if err = m.m.WriteHeader(streams); err != nil {
|
||||
return
|
||||
}
|
||||
meta, fist := m.m.GetInit(streams)
|
||||
if err = wsutil.WriteServerText(m.conn, []byte(meta)); err != nil {
|
||||
return
|
||||
}
|
||||
if err = wsutil.WriteServerBinary(m.conn, fist); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Muxer) WritePacket(pkt av.Packet) (err error) {
|
||||
gotFrame, buffer, err := m.m.WritePacket(pkt, false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if gotFrame {
|
||||
if err = wsutil.WriteServerBinary(m.conn, buffer); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Muxer) WriteTrailer() (err error) {
|
||||
|
||||
return m.conn.Close()
|
||||
}
|
@ -1,59 +1,383 @@
|
||||
package nvr
|
||||
|
||||
import (
|
||||
"log"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/gob"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/format/mp4"
|
||||
"github.com/google/uuid"
|
||||
"github.com/shirou/gopsutil/v3/disk"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
var MIME = []byte{11, 22, 111, 222, 11, 22, 111, 222}
|
||||
|
||||
var listTag = []string{"{server_id}", "{host_name}", "{host_name_short}", "{host_name_long}",
|
||||
"{stream_name}", "{channel_name}", "{stream_id}", "{channel_id}",
|
||||
"{start_year}", "{start_month}", "{start_day}", "{start_hour}", "{start_minute}", "{start_second}",
|
||||
"{start_millisecond}", "{start_unix_second}", "{start_unix_millisecond}", "{start_time}", "{start_pts}",
|
||||
"{end_year}", "{end_month}", "{end_day}", "{end_hour}", "{end_minute}", "{end_second}",
|
||||
"{end_millisecond}", "{end_unix_millisecond}", "{end_unix_second}", "{end_time}", "{end_pts}", "{duration_second}", "{duration_millisecond}"}
|
||||
|
||||
const (
|
||||
MP4 = "mp4"
|
||||
NVR = "nvr"
|
||||
)
|
||||
|
||||
type Muxer struct {
|
||||
name string
|
||||
muxer *mp4.Muxer
|
||||
format string
|
||||
limit int
|
||||
d *os.File
|
||||
m *os.File
|
||||
dur time.Duration
|
||||
h int
|
||||
gof *Gof
|
||||
patch string
|
||||
mpoint []string
|
||||
start, end time.Time
|
||||
pstart, pend time.Duration
|
||||
started bool
|
||||
file *os.File
|
||||
codec []av.CodecData
|
||||
buffer []*av.Packet
|
||||
bufferDur time.Duration
|
||||
seqDur time.Duration
|
||||
serverID, streamName, channelName, streamID, channelID, hostLong, hostShort string
|
||||
handleFileChange func(bool, string, string, int64, time.Time, time.Time, time.Duration)
|
||||
}
|
||||
|
||||
//NewMuxer func
|
||||
func NewMuxer(codec []av.CodecData, name, patch string, seqDur time.Duration) *Muxer {
|
||||
return &Muxer{
|
||||
codec: codec,
|
||||
name: name,
|
||||
type Gof struct {
|
||||
Streams []av.CodecData
|
||||
Packet []av.Packet
|
||||
}
|
||||
|
||||
type Data struct {
|
||||
Time int64
|
||||
Start int64
|
||||
Dur int64
|
||||
}
|
||||
|
||||
const (
|
||||
B = 1
|
||||
KB = 1024 * B
|
||||
MB = 1024 * KB
|
||||
GB = 1024 * MB
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.RegisterName("nvr.Gof", Gof{})
|
||||
gob.RegisterName("h264parser.CodecData", h264parser.CodecData{})
|
||||
gob.RegisterName("aacparser.CodecData", aacparser.CodecData{})
|
||||
|
||||
}
|
||||
|
||||
func NewMuxer(serverID, streamName, channelName, streamID, channelID string, mpoint []string, patch, format string, limit int, c func(bool, string, string, int64, time.Time, time.Time, time.Duration)) (m *Muxer, err error) {
|
||||
hostLong, _ := os.Hostname()
|
||||
var hostShort string
|
||||
if p, _, ok := strings.Cut(hostLong, "."); ok {
|
||||
hostShort = p
|
||||
}
|
||||
m = &Muxer{
|
||||
mpoint: mpoint,
|
||||
patch: patch,
|
||||
seqDur: seqDur,
|
||||
h: -1,
|
||||
gof: &Gof{},
|
||||
format: format,
|
||||
limit: limit,
|
||||
serverID: serverID,
|
||||
streamName: streamName,
|
||||
channelName: channelName,
|
||||
streamID: streamID,
|
||||
channelID: channelID,
|
||||
hostLong: hostLong,
|
||||
hostShort: hostShort,
|
||||
handleFileChange: c,
|
||||
}
|
||||
}
|
||||
|
||||
//WritePacket func
|
||||
func (obj *Muxer) CodecUpdate(val []av.CodecData) {
|
||||
obj.codec = val
|
||||
}
|
||||
|
||||
//WritePacket func
|
||||
func (obj *Muxer) WritePacket(pkt *av.Packet) (err error) {
|
||||
if !obj.started && pkt.IsKeyFrame {
|
||||
obj.started = true
|
||||
}
|
||||
if obj.started {
|
||||
if pkt.IsKeyFrame && obj.bufferDur >= obj.seqDur {
|
||||
log.Println("write to drive", len(obj.buffer), obj.bufferDur)
|
||||
obj.buffer = nil
|
||||
obj.bufferDur = 0
|
||||
}
|
||||
obj.buffer = append(obj.buffer, pkt)
|
||||
if pkt.Idx == 0 {
|
||||
obj.bufferDur += pkt.Duration
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//Close func
|
||||
func (obj *Muxer) Close() {
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Muxer) WriteHeader(streams []av.CodecData) (err error) {
|
||||
m.gof.Streams = streams
|
||||
if m.format == MP4 {
|
||||
return m.OpenMP4()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Muxer) WritePacket(pkt av.Packet) (err error) {
|
||||
if len(m.gof.Streams) == 0 {
|
||||
return
|
||||
}
|
||||
if !m.started && pkt.IsKeyFrame {
|
||||
m.started = true
|
||||
}
|
||||
if m.started {
|
||||
switch m.format {
|
||||
case MP4:
|
||||
return m.writePacketMP4(pkt)
|
||||
case NVR:
|
||||
return m.writePacketNVR(pkt)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Muxer) writePacketMP4(pkt av.Packet) (err error) {
|
||||
if pkt.IsKeyFrame && m.dur > time.Duration(m.limit)*time.Second {
|
||||
m.pstart = pkt.Time
|
||||
if err = m.OpenMP4(); err != nil {
|
||||
return
|
||||
}
|
||||
m.dur = 0
|
||||
|
||||
}
|
||||
m.dur += pkt.Duration
|
||||
m.pend = pkt.Time
|
||||
|
||||
return m.muxer.WritePacket(pkt)
|
||||
}
|
||||
|
||||
func (m *Muxer) writePacketNVR(pkt av.Packet) (err error) {
|
||||
if pkt.IsKeyFrame {
|
||||
if len(m.gof.Packet) > 0 {
|
||||
if err = m.writeGop(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
m.gof.Packet, m.dur = nil, 0
|
||||
}
|
||||
if pkt.Idx == 0 {
|
||||
m.dur += pkt.Duration
|
||||
}
|
||||
m.gof.Packet = append(m.gof.Packet, pkt)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Muxer) writeGop() (err error) {
|
||||
t := time.Now().UTC()
|
||||
if m.h != t.Hour() {
|
||||
if err = m.OpenNVR(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
f := Data{
|
||||
Time: t.UnixNano(),
|
||||
Dur: m.dur.Milliseconds(),
|
||||
}
|
||||
if f.Start, err = m.d.Seek(0, 2); err != nil {
|
||||
return
|
||||
}
|
||||
enc := gob.NewEncoder(m.d)
|
||||
if err = enc.Encode(m.gof); err != nil {
|
||||
return
|
||||
}
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
if err = binary.Write(buf, binary.LittleEndian, f); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = buf.Write(MIME); err != nil {
|
||||
return
|
||||
}
|
||||
_, err = m.m.Write(buf.Bytes())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Muxer) OpenNVR() (err error) {
|
||||
m.WriteTrailer()
|
||||
t := time.Now().UTC()
|
||||
if err = os.MkdirAll(fmt.Sprintf("%s/%s", m.patch, t.Format("2006/01/02")), 0755); err != nil {
|
||||
return
|
||||
}
|
||||
if m.d, err = os.OpenFile(fmt.Sprintf("%s/%s/%d.d", m.patch, t.Format("2006/01/02"), t.Hour()), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660); err != nil {
|
||||
return
|
||||
}
|
||||
if m.m, err = os.OpenFile(fmt.Sprintf("%s/%s/%d.m", m.patch, t.Format("2006/01/02"), t.Hour()), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660); err != nil {
|
||||
return
|
||||
}
|
||||
m.h = t.Hour()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Muxer) OpenMP4() (err error) {
|
||||
m.WriteTrailer()
|
||||
m.start = time.Now().UTC()
|
||||
|
||||
d, err := m.filePatch()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err = os.MkdirAll(filepath.Dir(d), 0755); err != nil {
|
||||
return
|
||||
}
|
||||
name := filepath.Join(filepath.Dir(d), fmt.Sprintf("tmp_%s_%d.mp4", uuid.New(), time.Now().Unix()))
|
||||
if m.d, err = os.Create(name); err != nil {
|
||||
return
|
||||
}
|
||||
m.handleFileChange(
|
||||
true,
|
||||
m.Codecs(),
|
||||
name,
|
||||
0,
|
||||
m.start,
|
||||
m.end,
|
||||
m.dur,
|
||||
)
|
||||
|
||||
m.muxer = mp4.NewMuxer(m.d)
|
||||
m.muxer.NegativeTsMakeZero = true
|
||||
if err = m.muxer.WriteHeader(m.gof.Streams); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Muxer) filePatch() (string, error) {
|
||||
var (
|
||||
mu = float64(100)
|
||||
ui = -1
|
||||
)
|
||||
|
||||
for i, i2 := range m.mpoint {
|
||||
//if m, err := mountinfo.Mounted(i2); err == nil && m {
|
||||
if d, err := disk.Usage(i2); err == nil {
|
||||
if d.UsedPercent < mu {
|
||||
ui = i
|
||||
mu = d.UsedPercent
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
if ui == -1 {
|
||||
return "", errors.New("not mount ready")
|
||||
}
|
||||
|
||||
ts := filepath.Join(m.mpoint[ui], m.patch)
|
||||
m.end = time.Now().UTC()
|
||||
|
||||
for _, s := range listTag {
|
||||
switch s {
|
||||
case "{server_id}":
|
||||
ts = strings.Replace(ts, "{server_id}", m.serverID, -1)
|
||||
case "{host_name}":
|
||||
ts = strings.Replace(ts, "{host_name}", m.hostLong, -1)
|
||||
case "{host_name_short}":
|
||||
ts = strings.Replace(ts, "{host_name_short}", m.hostShort, -1)
|
||||
case "{host_name_long}":
|
||||
ts = strings.Replace(ts, "{host_name_long}", m.hostLong, -1)
|
||||
case "{stream_name}":
|
||||
ts = strings.Replace(ts, "{stream_name}", m.streamName, -1)
|
||||
case "{channel_name}":
|
||||
ts = strings.Replace(ts, "{channel_name}", m.channelName, -1)
|
||||
case "{stream_id}":
|
||||
ts = strings.Replace(ts, "{stream_id}", m.streamID, -1)
|
||||
case "{channel_id}":
|
||||
ts = strings.Replace(ts, "{channel_id}", m.channelID, -1)
|
||||
case "{start_year}":
|
||||
ts = strings.Replace(ts, "{start_year}", fmt.Sprintf("%d", m.start.Year()), -1)
|
||||
case "{start_month}":
|
||||
ts = strings.Replace(ts, "{start_month}", fmt.Sprintf("%02d", int(m.start.Month())), -1)
|
||||
case "{start_day}":
|
||||
ts = strings.Replace(ts, "{start_day}", fmt.Sprintf("%02d", m.start.Day()), -1)
|
||||
case "{start_hour}":
|
||||
ts = strings.Replace(ts, "{start_hour}", fmt.Sprintf("%02d", m.start.Hour()), -1)
|
||||
case "{start_minute}":
|
||||
ts = strings.Replace(ts, "{start_minute}", fmt.Sprintf("%02d", m.start.Minute()), -1)
|
||||
case "{start_second}":
|
||||
ts = strings.Replace(ts, "{start_second}", fmt.Sprintf("%02d", m.start.Second()), -1)
|
||||
case "{start_millisecond}":
|
||||
ts = strings.Replace(ts, "{start_millisecond}", fmt.Sprintf("%d", m.start.Nanosecond()/1000/1000), -1)
|
||||
case "{start_unix_millisecond}":
|
||||
ts = strings.Replace(ts, "{start_unix_millisecond}", fmt.Sprintf("%d", m.start.UnixMilli()), -1)
|
||||
case "{start_unix_second}":
|
||||
ts = strings.Replace(ts, "{start_unix_second}", fmt.Sprintf("%d", m.start.Unix()), -1)
|
||||
case "{start_time}":
|
||||
ts = strings.Replace(ts, "{start_time}", fmt.Sprintf("%s", m.start.Format("2006-01-02T15:04:05-0700")), -1)
|
||||
case "{start_pts}":
|
||||
ts = strings.Replace(ts, "{start_pts}", fmt.Sprintf("%d", m.pstart.Milliseconds()), -1)
|
||||
case "{end_year}":
|
||||
ts = strings.Replace(ts, "{end_year}", fmt.Sprintf("%d", m.end.Year()), -1)
|
||||
case "{end_month}":
|
||||
ts = strings.Replace(ts, "{end_month}", fmt.Sprintf("%02d", int(m.end.Month())), -1)
|
||||
case "{end_day}":
|
||||
ts = strings.Replace(ts, "{end_day}", fmt.Sprintf("%02d", m.end.Day()), -1)
|
||||
case "{end_hour}":
|
||||
ts = strings.Replace(ts, "{end_hour}", fmt.Sprintf("%02d", m.end.Hour()), -1)
|
||||
case "{end_minute}":
|
||||
ts = strings.Replace(ts, "{end_minute}", fmt.Sprintf("%02d", m.end.Minute()), -1)
|
||||
case "{end_second}":
|
||||
ts = strings.Replace(ts, "{end_second}", fmt.Sprintf("%02d", m.end.Second()), -1)
|
||||
case "{end_millisecond}":
|
||||
ts = strings.Replace(ts, "{end_millisecond}", fmt.Sprintf("%d", m.end.Nanosecond()/1000/1000), -1)
|
||||
case "{end_unix_millisecond}":
|
||||
ts = strings.Replace(ts, "{end_unix_millisecond}", fmt.Sprintf("%d", m.end.UnixMilli()), -1)
|
||||
case "{end_unix_second}":
|
||||
ts = strings.Replace(ts, "{end_unix_second}", fmt.Sprintf("%d", m.end.Unix()), -1)
|
||||
case "{end_time}":
|
||||
ts = strings.Replace(ts, "{end_time}", fmt.Sprintf("%s", m.end.Format("2006-01-02T15:04:05-0700")), -1)
|
||||
case "{end_pts}":
|
||||
ts = strings.Replace(ts, "{end_pts}", fmt.Sprintf("%d", m.pend.Milliseconds()), -1)
|
||||
case "{duration_second}":
|
||||
ts = strings.Replace(ts, "{duration_second}", fmt.Sprintf("%f", m.dur.Seconds()), -1)
|
||||
case "{duration_millisecond}":
|
||||
ts = strings.Replace(ts, "{duration_millisecond}", fmt.Sprintf("%d", m.dur.Milliseconds()), -1)
|
||||
}
|
||||
}
|
||||
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
func (m *Muxer) Codecs() string {
|
||||
var codecs []string
|
||||
for _, stream := range m.gof.Streams {
|
||||
codecs = append(codecs, strings.ToLower(stream.Type().String()))
|
||||
}
|
||||
|
||||
return strings.Join(codecs, ",")
|
||||
}
|
||||
|
||||
func (m *Muxer) WriteTrailer() (err error) {
|
||||
if m.muxer != nil {
|
||||
m.muxer.WriteTrailer()
|
||||
}
|
||||
if m.m != nil {
|
||||
err = m.m.Close()
|
||||
}
|
||||
if m.d != nil {
|
||||
if m.format == MP4 {
|
||||
p, err := m.filePatch()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = os.Rename(m.d.Name(), filepath.Join(filepath.Dir(m.d.Name()), filepath.Base(p))); err != nil {
|
||||
return err
|
||||
}
|
||||
var size int64
|
||||
if fi, err := m.d.Stat(); err == nil {
|
||||
size = fi.Size()
|
||||
}
|
||||
m.handleFileChange(
|
||||
false,
|
||||
m.Codecs(),
|
||||
filepath.Join(filepath.Dir(m.d.Name()), filepath.Base(p)),
|
||||
size,
|
||||
m.start,
|
||||
m.end,
|
||||
m.dur,
|
||||
)
|
||||
}
|
||||
err = m.d.Close()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
8
format/nvr/streams.go
Normal file
8
format/nvr/streams.go
Normal file
@ -0,0 +1,8 @@
|
||||
package nvr
|
||||
|
||||
import "git.r-2.top/kunmeng/vdk/av"
|
||||
|
||||
type Stream struct {
|
||||
codec av.CodecData
|
||||
idx int
|
||||
}
|
@ -4,11 +4,11 @@ import (
|
||||
"bytes"
|
||||
"os"
|
||||
|
||||
"github.com/deepch/vdk/codec/h265parser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h265parser"
|
||||
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
)
|
||||
|
||||
var startCode = []byte{0, 0, 0, 1}
|
||||
|
@ -14,11 +14,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/av/avutil"
|
||||
"github.com/deepch/vdk/format/flv"
|
||||
"github.com/deepch/vdk/format/flv/flvio"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av/avutil"
|
||||
"git.r-2.top/kunmeng/vdk/format/flv"
|
||||
"git.r-2.top/kunmeng/vdk/format/flv/flvio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
var Debug bool
|
||||
@ -258,8 +258,11 @@ func (self *Conn) RxBytes() uint64 {
|
||||
}
|
||||
|
||||
func (self *Conn) Close() (err error) {
|
||||
if self.netconn != nil {
|
||||
return self.netconn.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Conn) pollCommand() (err error) {
|
||||
for {
|
||||
@ -1623,20 +1626,15 @@ func (self *Conn) handshakeServer() (err error) {
|
||||
clitime := pio.U32BE(C1[0:4])
|
||||
srvtime := clitime
|
||||
srvver := uint32(0x0d0e0a0d)
|
||||
cliver := pio.U32BE(C1[4:8])
|
||||
|
||||
if cliver != 0 {
|
||||
var ok bool
|
||||
var digest []byte
|
||||
if ok, digest = hsParse1(C1, hsClientPartialKey, hsServerFullKey); !ok {
|
||||
err = fmt.Errorf("rtmp: handshake server: C1 invalid")
|
||||
return
|
||||
}
|
||||
if ok, digest = hsParse1(C1, hsClientPartialKey, hsServerFullKey); ok {
|
||||
hsCreate01(S0S1, srvtime, srvver, hsServerPartialKey)
|
||||
hsCreate2(S2, digest)
|
||||
} else {
|
||||
copy(S1, C1)
|
||||
copy(S2, C2)
|
||||
copy(S1, C2)
|
||||
copy(S2, C1)
|
||||
}
|
||||
|
||||
if _, err = self.bufw.Write(S0S1S2); err != nil {
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
//"log"
|
||||
"net"
|
||||
"net/textproto"
|
||||
"net/url"
|
||||
@ -17,13 +16,13 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/av/avutil"
|
||||
"github.com/deepch/vdk/codec"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/format/rtsp/sdp"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av/avutil"
|
||||
"git.r-2.top/kunmeng/vdk/codec"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/format/rtsp/sdp"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
var ErrCodecDataChange = fmt.Errorf("rtsp: codec data change, please call HandleCodecDataChange()")
|
||||
@ -43,6 +42,7 @@ const (
|
||||
type Client struct {
|
||||
DebugRtsp bool
|
||||
DebugRtp bool
|
||||
DisableAudio bool
|
||||
Headers []string
|
||||
|
||||
SkipErrRtpBlock bool
|
||||
@ -147,7 +147,12 @@ func (self *Client) probe() (err error) {
|
||||
}
|
||||
|
||||
func (self *Client) prepare(stage int) (err error) {
|
||||
var waitIdle int
|
||||
for self.stage < stage {
|
||||
waitIdle++
|
||||
if waitIdle > 20 {
|
||||
return fmt.Errorf("codec not ready")
|
||||
}
|
||||
switch self.stage {
|
||||
case 0:
|
||||
if err = self.Options(); err != nil {
|
||||
@ -695,7 +700,9 @@ func (self *Client) Describe() (streams []sdp.Media, err error) {
|
||||
self.streams = []*Stream{}
|
||||
for _, media := range medias {
|
||||
stream := &Stream{Sdp: media, client: self}
|
||||
stream.makeCodecData()
|
||||
if err = stream.makeCodecData(); err != nil && DebugRtsp {
|
||||
fmt.Println("rtsp: makeCodecData error", err)
|
||||
}
|
||||
self.streams = append(self.streams, stream)
|
||||
streams = append(streams, media)
|
||||
}
|
||||
@ -767,7 +774,7 @@ func (self *Stream) timeScale() int {
|
||||
|
||||
func (self *Stream) makeCodecData() (err error) {
|
||||
media := self.Sdp
|
||||
if media.PayloadType >= 96 && media.PayloadType <= 127 {
|
||||
if (media.PayloadType >= 96 && media.PayloadType <= 127) || media.Type == av.H264 || media.Type == av.AAC {
|
||||
switch media.Type {
|
||||
case av.H264:
|
||||
for _, nalu := range media.SpropParameterSets {
|
||||
@ -1070,12 +1077,44 @@ func (self *Stream) handleRtpPacket(packet []byte) (err error) {
|
||||
err = fmt.Errorf("rtp: packet too short")
|
||||
return
|
||||
}
|
||||
payloadOffset := 12 + int(packet[0]&0xf)*4
|
||||
|
||||
timestamp := binary.BigEndian.Uint32(packet[4:8])
|
||||
|
||||
/*
|
||||
Test offset
|
||||
*/
|
||||
Padding := (packet[0]>>5)&1 == 1
|
||||
Extension := (packet[0]>>4)&1 == 1
|
||||
CSRCCnt := int(packet[0] & 0x0f)
|
||||
|
||||
RTPHeaderSize := 12
|
||||
|
||||
payloadOffset := RTPHeaderSize
|
||||
end := len(packet)
|
||||
if end-payloadOffset >= 4*CSRCCnt {
|
||||
payloadOffset += 4 * CSRCCnt
|
||||
}
|
||||
|
||||
if Extension && end-payloadOffset >= 4 {
|
||||
extLen := 4 * int(binary.BigEndian.Uint16(packet[payloadOffset+2:]))
|
||||
payloadOffset += 4
|
||||
if end-payloadOffset >= extLen {
|
||||
payloadOffset += extLen
|
||||
}
|
||||
}
|
||||
|
||||
if Padding && end-payloadOffset > 0 {
|
||||
paddingLen := int(packet[end-1])
|
||||
if end-payloadOffset >= paddingLen {
|
||||
end -= paddingLen
|
||||
}
|
||||
}
|
||||
|
||||
if payloadOffset > len(packet) {
|
||||
err = fmt.Errorf("rtp: packet too short")
|
||||
return
|
||||
}
|
||||
timestamp := binary.BigEndian.Uint32(packet[4:8])
|
||||
|
||||
payload := packet[payloadOffset:]
|
||||
|
||||
/*
|
||||
@ -1152,6 +1191,7 @@ func (self *Client) Play() (err error) {
|
||||
Method: "PLAY",
|
||||
Uri: self.requestUri,
|
||||
}
|
||||
req.Header = append(req.Header, "Range: npt=0.000-")
|
||||
req.Header = append(req.Header, "Session: "+self.session)
|
||||
if err = self.WriteRequest(req); err != nil {
|
||||
return
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
@ -160,6 +160,9 @@ func Parse(content string) (sess Session, medias []Media) {
|
||||
case "sprop-parameter-sets":
|
||||
fields := strings.Split(val, ",")
|
||||
for _, field := range fields {
|
||||
if field == "" {
|
||||
continue
|
||||
}
|
||||
val, _ := base64.StdEncoding.DecodeString(field)
|
||||
media.SpropParameterSets = append(media.SpropParameterSets, val)
|
||||
}
|
||||
|
1
format/rtsp/server.go
Normal file
1
format/rtsp/server.go
Normal file
@ -0,0 +1 @@
|
||||
package rtsp
|
@ -3,8 +3,8 @@ package rtsp
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/format/rtsp/sdp"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/format/rtsp/sdp"
|
||||
)
|
||||
|
||||
type Stream struct {
|
||||
|
@ -12,19 +12,18 @@ import (
|
||||
"html"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/codec/h265parser"
|
||||
"github.com/deepch/vdk/format/rtsp/sdp"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h265parser"
|
||||
"git.r-2.top/kunmeng/vdk/format/rtsp/sdp"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -39,7 +38,10 @@ const (
|
||||
|
||||
const (
|
||||
RTPHeaderSize = 12
|
||||
RTCPSenderReport = 200
|
||||
RTCPReceiverReport = 201
|
||||
)
|
||||
|
||||
const (
|
||||
DESCRIBE = "DESCRIBE"
|
||||
OPTIONS = "OPTIONS"
|
||||
@ -90,6 +92,10 @@ type RTSPClient struct {
|
||||
FPS int
|
||||
WaitCodec bool
|
||||
chTMP int
|
||||
timestamp int64
|
||||
sequenceNumber int
|
||||
end int
|
||||
offset int
|
||||
}
|
||||
|
||||
type RTSPClientOptions struct {
|
||||
@ -147,9 +153,12 @@ func Dial(options RTSPClientOptions) (*RTSPClient, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, i2 := range client.mediaSDP {
|
||||
if (i2.AVType != VIDEO && i2.AVType != AUDIO) || (client.options.DisableAudio && i2.AVType == AUDIO) {
|
||||
//TODO check it
|
||||
if strings.Contains(string(client.SDPRaw), "LaunchDigital") {
|
||||
client.chTMP += 2
|
||||
}
|
||||
continue
|
||||
}
|
||||
err = client.request(SETUP, map[string]string{"Transport": "RTP/AVP/TCP;unicast;interleaved=" + strconv.Itoa(client.chTMP) + "-" + strconv.Itoa(client.chTMP+1)}, client.ControlTrack(i2.Control), false, false)
|
||||
@ -238,6 +247,146 @@ func Dial(options RTSPClientOptions) (*RTSPClient, error) {
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func ReplayDial(options RTSPClientOptions, startTime string) (*RTSPClient, error) {
|
||||
client := &RTSPClient{
|
||||
headers: make(map[string]string),
|
||||
Signals: make(chan int, 100),
|
||||
OutgoingProxyQueue: make(chan *[]byte, 3000),
|
||||
OutgoingPacketQueue: make(chan *av.Packet, 3000),
|
||||
BufferRtpPacket: bytes.NewBuffer([]byte{}),
|
||||
videoID: -1,
|
||||
audioID: -2,
|
||||
videoIDX: -1,
|
||||
audioIDX: -2,
|
||||
options: options,
|
||||
AudioTimeScale: 8000,
|
||||
}
|
||||
client.headers["User-Agent"] = "Lavf58.76.100"
|
||||
err := client.parseURL(html.UnescapeString(client.options.URL))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := net.DialTimeout("tcp", client.pURL.Host, client.options.DialTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = conn.SetDeadline(time.Now().Add(client.options.ReadWriteTimeout))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if client.pURL.Scheme == "rtsps" {
|
||||
tlsConn := tls.Client(conn, &tls.Config{InsecureSkipVerify: options.InsecureSkipVerify, ServerName: client.pURL.Hostname()})
|
||||
err = tlsConn.Handshake()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn = tlsConn
|
||||
}
|
||||
client.conn = conn
|
||||
client.connRW = bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
|
||||
err = client.request(OPTIONS, nil, client.pURL.String(), false, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = client.request(DESCRIBE, map[string]string{"Accept": "application/sdp"}, client.pURL.String(), false, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, i2 := range client.mediaSDP {
|
||||
if (i2.AVType != VIDEO && i2.AVType != AUDIO) || (client.options.DisableAudio && i2.AVType == AUDIO) {
|
||||
//TODO check it
|
||||
if strings.Contains(string(client.SDPRaw), "LaunchDigital") {
|
||||
client.chTMP += 2
|
||||
}
|
||||
continue
|
||||
}
|
||||
// err = client.request(SETUP, map[string]string{"Require": "onvif-replay", "Transport": "RTP/UDP"}, client.ControlTrack(i2.Control), false, false)
|
||||
err = client.request(SETUP, map[string]string{"Require": "onvif-replay", "Transport": "RTP/AVP/TCP;unicast;interleaved=" + strconv.Itoa(client.chTMP) + "-" + strconv.Itoa(client.chTMP+1)}, client.ControlTrack(i2.Control), false, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if i2.AVType == VIDEO {
|
||||
if i2.Type == av.H264 {
|
||||
if len(i2.SpropParameterSets) > 1 {
|
||||
if codecData, err := h264parser.NewCodecDataFromSPSAndPPS(i2.SpropParameterSets[0], i2.SpropParameterSets[1]); err == nil {
|
||||
client.sps = i2.SpropParameterSets[0]
|
||||
client.pps = i2.SpropParameterSets[1]
|
||||
client.CodecData = append(client.CodecData, codecData)
|
||||
}
|
||||
} else {
|
||||
client.CodecData = append(client.CodecData, h264parser.CodecData{})
|
||||
client.WaitCodec = true
|
||||
}
|
||||
client.FPS = i2.FPS
|
||||
client.videoCodec = av.H264
|
||||
} else if i2.Type == av.H265 {
|
||||
if len(i2.SpropVPS) > 1 && len(i2.SpropSPS) > 1 && len(i2.SpropPPS) > 1 {
|
||||
if codecData, err := h265parser.NewCodecDataFromVPSAndSPSAndPPS(i2.SpropVPS, i2.SpropSPS, i2.SpropPPS); err == nil {
|
||||
client.vps = i2.SpropVPS
|
||||
client.sps = i2.SpropSPS
|
||||
client.pps = i2.SpropPPS
|
||||
client.CodecData = append(client.CodecData, codecData)
|
||||
}
|
||||
} else {
|
||||
client.CodecData = append(client.CodecData, h265parser.CodecData{})
|
||||
}
|
||||
client.videoCodec = av.H265
|
||||
|
||||
} else {
|
||||
client.Println("SDP Video Codec Type Not Supported", i2.Type)
|
||||
}
|
||||
client.videoIDX = int8(len(client.CodecData) - 1)
|
||||
client.videoID = client.chTMP
|
||||
}
|
||||
if i2.AVType == AUDIO {
|
||||
client.audioID = client.chTMP
|
||||
var CodecData av.AudioCodecData
|
||||
switch i2.Type {
|
||||
case av.AAC:
|
||||
CodecData, err = aacparser.NewCodecDataFromMPEG4AudioConfigBytes(i2.Config)
|
||||
if err == nil {
|
||||
client.Println("Audio AAC bad config")
|
||||
}
|
||||
case av.OPUS:
|
||||
var cl av.ChannelLayout
|
||||
switch i2.ChannelCount {
|
||||
case 1:
|
||||
cl = av.CH_MONO
|
||||
case 2:
|
||||
cl = av.CH_STEREO
|
||||
default:
|
||||
cl = av.CH_MONO
|
||||
}
|
||||
CodecData = codec.NewOpusCodecData(i2.TimeScale, cl)
|
||||
case av.PCM_MULAW:
|
||||
CodecData = codec.NewPCMMulawCodecData()
|
||||
case av.PCM_ALAW:
|
||||
CodecData = codec.NewPCMAlawCodecData()
|
||||
case av.PCM:
|
||||
CodecData = codec.NewPCMCodecData()
|
||||
default:
|
||||
client.Println("Audio Codec", i2.Type, "not supported")
|
||||
}
|
||||
if CodecData != nil {
|
||||
client.CodecData = append(client.CodecData, CodecData)
|
||||
client.audioIDX = int8(len(client.CodecData) - 1)
|
||||
client.audioCodec = CodecData.Type()
|
||||
if i2.TimeScale != 0 {
|
||||
client.AudioTimeScale = int64(i2.TimeScale)
|
||||
}
|
||||
}
|
||||
}
|
||||
client.chTMP += 2
|
||||
}
|
||||
test := map[string]string{"Require": "onvif-replay", "Scale": "1.000000", "Speed": "1.000000", "Range": "clock=" + startTime + "-"}
|
||||
err = client.request(PLAY, test, client.control, false, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
go client.startStream()
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (client *RTSPClient) ControlTrack(track string) string {
|
||||
if strings.Contains(track, "rtsp://") {
|
||||
return track
|
||||
@ -548,285 +697,6 @@ func stringInBetween(str string, start string, end string) (result string) {
|
||||
return str
|
||||
}
|
||||
|
||||
func (client *RTSPClient) RTPDemuxer(payloadRAW *[]byte) ([]*av.Packet, bool) {
|
||||
|
||||
content := *payloadRAW
|
||||
firstByte := content[4]
|
||||
padding := (firstByte>>5)&1 == 1
|
||||
extension := (firstByte>>4)&1 == 1
|
||||
CSRCCnt := int(firstByte & 0x0f)
|
||||
SequenceNumber := int(binary.BigEndian.Uint16(content[6:8]))
|
||||
timestamp := int64(binary.BigEndian.Uint32(content[8:16]))
|
||||
|
||||
offset := RTPHeaderSize
|
||||
|
||||
end := len(content)
|
||||
if end-offset >= 4*CSRCCnt {
|
||||
offset += 4 * CSRCCnt
|
||||
}
|
||||
if extension && len(content) < 4+offset+2+2 {
|
||||
return nil, false
|
||||
}
|
||||
if extension && end-offset >= 4 {
|
||||
extLen := 4 * int(binary.BigEndian.Uint16(content[4+offset+2:]))
|
||||
offset += 4
|
||||
if end-offset >= extLen {
|
||||
offset += extLen
|
||||
}
|
||||
}
|
||||
if padding && end-offset > 0 {
|
||||
paddingLen := int(content[end-1])
|
||||
if end-offset >= paddingLen {
|
||||
end -= paddingLen
|
||||
}
|
||||
}
|
||||
offset += 4
|
||||
switch int(content[1]) {
|
||||
case client.videoID:
|
||||
if client.PreVideoTS == 0 {
|
||||
client.PreVideoTS = timestamp
|
||||
}
|
||||
if timestamp-client.PreVideoTS < 0 {
|
||||
if math.MaxUint32-client.PreVideoTS < 90*100 { //100 ms
|
||||
client.PreVideoTS = 0
|
||||
client.PreVideoTS -= (math.MaxUint32 - client.PreVideoTS)
|
||||
} else {
|
||||
client.PreVideoTS = 0
|
||||
}
|
||||
}
|
||||
if client.PreSequenceNumber != 0 && SequenceNumber-client.PreSequenceNumber != 1 {
|
||||
client.Println("drop packet", SequenceNumber-1)
|
||||
}
|
||||
client.PreSequenceNumber = SequenceNumber
|
||||
if client.BufferRtpPacket.Len() > 4048576 {
|
||||
client.Println("Big Buffer Flush")
|
||||
client.BufferRtpPacket.Truncate(0)
|
||||
client.BufferRtpPacket.Reset()
|
||||
}
|
||||
nalRaw, _ := h264parser.SplitNALUs(content[offset:end])
|
||||
if len(nalRaw) == 0 || len(nalRaw[0]) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
var retmap []*av.Packet
|
||||
for _, nal := range nalRaw {
|
||||
if client.videoCodec == av.H265 {
|
||||
naluType := (nal[0] >> 1) & 0x3f
|
||||
switch naluType {
|
||||
case h265parser.NAL_UNIT_CODED_SLICE_TRAIL_R:
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: append(binSize(len(nal)), nal...),
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Idx: client.videoIDX,
|
||||
IsKeyFrame: false,
|
||||
Duration: time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond,
|
||||
Time: time.Duration(timestamp/90) * time.Millisecond,
|
||||
})
|
||||
case h265parser.NAL_UNIT_VPS:
|
||||
client.CodecUpdateVPS(nal)
|
||||
case h265parser.NAL_UNIT_SPS:
|
||||
client.CodecUpdateSPS(nal)
|
||||
case h265parser.NAL_UNIT_PPS:
|
||||
client.CodecUpdatePPS(nal)
|
||||
case h265parser.NAL_UNIT_UNSPECIFIED_49:
|
||||
se := nal[2] >> 6
|
||||
naluType := nal[2] & 0x3f
|
||||
if se == 2 {
|
||||
client.BufferRtpPacket.Truncate(0)
|
||||
client.BufferRtpPacket.Reset()
|
||||
client.BufferRtpPacket.Write([]byte{(nal[0] & 0x81) | (naluType << 1), nal[1]})
|
||||
r := make([]byte, 2)
|
||||
r[1] = nal[1]
|
||||
r[0] = (nal[0] & 0x81) | (naluType << 1)
|
||||
client.BufferRtpPacket.Write(nal[3:])
|
||||
} else if se == 1 {
|
||||
client.BufferRtpPacket.Write(nal[3:])
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: append(binSize(client.BufferRtpPacket.Len()), client.BufferRtpPacket.Bytes()...),
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Idx: client.videoIDX,
|
||||
IsKeyFrame: naluType == h265parser.NAL_UNIT_CODED_SLICE_IDR_W_RADL,
|
||||
Duration: time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond,
|
||||
Time: time.Duration(timestamp/90) * time.Millisecond,
|
||||
})
|
||||
} else {
|
||||
client.BufferRtpPacket.Write(nal[3:])
|
||||
}
|
||||
default:
|
||||
//client.Println("Unsupported Nal", naluType)
|
||||
}
|
||||
|
||||
} else if client.videoCodec == av.H264 {
|
||||
naluType := nal[0] & 0x1f
|
||||
switch {
|
||||
case naluType >= 1 && naluType <= 5:
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: append(binSize(len(nal)), nal...),
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Idx: client.videoIDX,
|
||||
IsKeyFrame: naluType == 5,
|
||||
Duration: time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond,
|
||||
Time: time.Duration(timestamp/90) * time.Millisecond,
|
||||
})
|
||||
case naluType == 7:
|
||||
client.CodecUpdateSPS(nal)
|
||||
case naluType == 8:
|
||||
client.CodecUpdatePPS(nal)
|
||||
case naluType == 24:
|
||||
packet := nal[1:]
|
||||
for len(packet) >= 2 {
|
||||
size := int(packet[0])<<8 | int(packet[1])
|
||||
if size+2 > len(packet) {
|
||||
break
|
||||
}
|
||||
naluTypefs := packet[2] & 0x1f
|
||||
switch {
|
||||
case naluTypefs >= 1 && naluTypefs <= 5:
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: append(binSize(len(packet[2:size+2])), packet[2:size+2]...),
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Idx: client.videoIDX,
|
||||
IsKeyFrame: naluType == 5,
|
||||
Duration: time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond,
|
||||
Time: time.Duration(timestamp/90) * time.Millisecond,
|
||||
})
|
||||
case naluTypefs == 7:
|
||||
client.CodecUpdateSPS(packet[2 : size+2])
|
||||
case naluTypefs == 8:
|
||||
client.CodecUpdatePPS(packet[2 : size+2])
|
||||
}
|
||||
packet = packet[size+2:]
|
||||
}
|
||||
case naluType == 28:
|
||||
fuIndicator := content[offset]
|
||||
fuHeader := content[offset+1]
|
||||
isStart := fuHeader&0x80 != 0
|
||||
isEnd := fuHeader&0x40 != 0
|
||||
if isStart {
|
||||
client.fuStarted = true
|
||||
client.BufferRtpPacket.Truncate(0)
|
||||
client.BufferRtpPacket.Reset()
|
||||
client.BufferRtpPacket.Write([]byte{fuIndicator&0xe0 | fuHeader&0x1f})
|
||||
}
|
||||
if client.fuStarted {
|
||||
client.BufferRtpPacket.Write(content[offset+2 : end])
|
||||
if isEnd {
|
||||
client.fuStarted = false
|
||||
naluTypef := client.BufferRtpPacket.Bytes()[0] & 0x1f
|
||||
if naluTypef == 7 || naluTypef == 9 {
|
||||
bufered, _ := h264parser.SplitNALUs(append([]byte{0, 0, 0, 1}, client.BufferRtpPacket.Bytes()...))
|
||||
for _, v := range bufered {
|
||||
naluTypefs := v[0] & 0x1f
|
||||
switch {
|
||||
case naluTypefs == 5:
|
||||
client.BufferRtpPacket.Reset()
|
||||
client.BufferRtpPacket.Write(v)
|
||||
naluTypef = 5
|
||||
case naluTypefs == 7:
|
||||
client.CodecUpdateSPS(v)
|
||||
case naluTypefs == 8:
|
||||
client.CodecUpdatePPS(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: append(binSize(client.BufferRtpPacket.Len()), client.BufferRtpPacket.Bytes()...),
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Duration: time.Duration(float32(timestamp-client.PreVideoTS)/90) * time.Millisecond,
|
||||
Idx: client.videoIDX,
|
||||
IsKeyFrame: naluTypef == 5,
|
||||
Time: time.Duration(timestamp/90) * time.Millisecond,
|
||||
})
|
||||
}
|
||||
}
|
||||
default:
|
||||
client.Println("Unsupported NAL Type", naluType)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(retmap) > 0 {
|
||||
client.PreVideoTS = timestamp
|
||||
return retmap, true
|
||||
}
|
||||
case client.audioID:
|
||||
if client.PreAudioTS == 0 {
|
||||
client.PreAudioTS = timestamp
|
||||
}
|
||||
nalRaw, _ := h264parser.SplitNALUs(content[offset:end])
|
||||
var retmap []*av.Packet
|
||||
for _, nal := range nalRaw {
|
||||
var duration time.Duration
|
||||
switch client.audioCodec {
|
||||
case av.PCM_MULAW:
|
||||
duration = time.Duration(len(nal)) * time.Second / time.Duration(client.AudioTimeScale)
|
||||
client.AudioTimeLine += duration
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: nal,
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Duration: duration,
|
||||
Idx: client.audioIDX,
|
||||
IsKeyFrame: false,
|
||||
Time: client.AudioTimeLine,
|
||||
})
|
||||
case av.PCM_ALAW:
|
||||
duration = time.Duration(len(nal)) * time.Second / time.Duration(client.AudioTimeScale)
|
||||
client.AudioTimeLine += duration
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: nal,
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Duration: duration,
|
||||
Idx: client.audioIDX,
|
||||
IsKeyFrame: false,
|
||||
Time: client.AudioTimeLine,
|
||||
})
|
||||
case av.OPUS:
|
||||
duration = time.Duration(20) * time.Millisecond
|
||||
client.AudioTimeLine += duration
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: nal,
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Duration: duration,
|
||||
Idx: client.audioIDX,
|
||||
IsKeyFrame: false,
|
||||
Time: client.AudioTimeLine,
|
||||
})
|
||||
case av.AAC:
|
||||
auHeadersLength := uint16(0) | (uint16(nal[0]) << 8) | uint16(nal[1])
|
||||
auHeadersCount := auHeadersLength >> 4
|
||||
framesPayloadOffset := 2 + int(auHeadersCount)<<1
|
||||
auHeaders := nal[2:framesPayloadOffset]
|
||||
framesPayload := nal[framesPayloadOffset:]
|
||||
for i := 0; i < int(auHeadersCount); i++ {
|
||||
auHeader := uint16(0) | (uint16(auHeaders[0]) << 8) | uint16(auHeaders[1])
|
||||
frameSize := auHeader >> 3
|
||||
frame := framesPayload[:frameSize]
|
||||
auHeaders = auHeaders[2:]
|
||||
framesPayload = framesPayload[frameSize:]
|
||||
if _, _, _, _, err := aacparser.ParseADTSHeader(frame); err == nil {
|
||||
frame = frame[7:]
|
||||
}
|
||||
duration = time.Duration((float32(1024)/float32(client.AudioTimeScale))*1000*1000*1000) * time.Nanosecond
|
||||
client.AudioTimeLine += duration
|
||||
retmap = append(retmap, &av.Packet{
|
||||
Data: frame,
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Duration: duration,
|
||||
Idx: client.audioIDX,
|
||||
IsKeyFrame: false,
|
||||
Time: client.AudioTimeLine,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(retmap) > 0 {
|
||||
client.PreAudioTS = timestamp
|
||||
return retmap, true
|
||||
}
|
||||
default:
|
||||
//client.Println("Unsuported Intervaled data packet", int(content[1]), content[offset:end])
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (client *RTSPClient) CodecUpdateSPS(val []byte) {
|
||||
if client.videoCodec != av.H264 && client.videoCodec != av.H265 {
|
||||
return
|
||||
@ -950,3 +820,8 @@ func binSize(val int) []byte {
|
||||
binary.BigEndian.PutUint32(buf, uint32(val))
|
||||
return buf
|
||||
}
|
||||
|
||||
func isRTCPPacket(content []byte) bool {
|
||||
rtcpPacketType := content[5]
|
||||
return rtcpPacketType == RTCPSenderReport || rtcpPacketType == RTCPReceiverReport
|
||||
}
|
||||
|
290
format/rtspv2/demuxer.go
Normal file
290
format/rtspv2/demuxer.go
Normal file
@ -0,0 +1,290 @@
|
||||
package rtspv2
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h265parser"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
TimeBaseFactor = 90
|
||||
TimeDelay = 1
|
||||
)
|
||||
|
||||
func (client *RTSPClient) RTPDemuxer(payloadRAW *[]byte) ([]*av.Packet, bool) {
|
||||
content := *payloadRAW
|
||||
firstByte := content[4]
|
||||
padding := (firstByte>>5)&1 == 1
|
||||
extension := (firstByte>>4)&1 == 1
|
||||
CSRCCnt := int(firstByte & 0x0f)
|
||||
client.sequenceNumber = int(binary.BigEndian.Uint16(content[6:8]))
|
||||
client.timestamp = int64(binary.BigEndian.Uint32(content[8:16]))
|
||||
|
||||
if isRTCPPacket(content) {
|
||||
client.Println("skipping RTCP packet")
|
||||
return nil, false
|
||||
}
|
||||
|
||||
client.offset = RTPHeaderSize
|
||||
|
||||
client.end = len(content)
|
||||
if client.end-client.offset >= 4*CSRCCnt {
|
||||
client.offset += 4 * CSRCCnt
|
||||
}
|
||||
extensionStart := 0
|
||||
extensionEnd := 0
|
||||
if extension && len(content) < 4+client.offset+2+2 {
|
||||
return nil, false
|
||||
}
|
||||
if extension && client.end-client.offset >= 4 {
|
||||
extLen := 4 * int(binary.BigEndian.Uint16(content[4+client.offset+2:]))
|
||||
client.offset += 4
|
||||
if client.end-client.offset >= extLen {
|
||||
extensionStart = client.offset
|
||||
extensionEnd = client.offset + extLen
|
||||
client.offset += extLen
|
||||
}
|
||||
}
|
||||
if padding && client.end-client.offset > 0 {
|
||||
paddingLen := int(content[client.end-1])
|
||||
if client.end-client.offset >= paddingLen {
|
||||
client.end -= paddingLen
|
||||
}
|
||||
}
|
||||
client.offset += 4
|
||||
if len(content) < client.end {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
switch int(content[1]) {
|
||||
case client.videoID:
|
||||
pck, ok := client.handleVideo(content)
|
||||
for _, p := range pck {
|
||||
p.Extension = extension
|
||||
p.Extensions = content[extensionStart+4 : extensionEnd+4]
|
||||
}
|
||||
return pck, ok
|
||||
case client.audioID:
|
||||
pck, ok := client.handleAudio(content)
|
||||
for _, p := range pck {
|
||||
p.Extension = extension
|
||||
p.Extensions = content[extensionStart+4 : extensionEnd+4]
|
||||
}
|
||||
return pck, ok
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (client *RTSPClient) handleVideo(content []byte) ([]*av.Packet, bool) {
|
||||
if client.PreVideoTS == 0 {
|
||||
client.PreVideoTS = client.timestamp
|
||||
}
|
||||
if client.timestamp-client.PreVideoTS < 0 {
|
||||
if math.MaxUint32-client.PreVideoTS < 90*100 { //100 ms
|
||||
client.PreVideoTS = 0
|
||||
client.PreVideoTS -= (math.MaxUint32 - client.PreVideoTS)
|
||||
} else {
|
||||
client.PreVideoTS = 0
|
||||
}
|
||||
}
|
||||
if client.PreSequenceNumber != 0 && client.sequenceNumber-client.PreSequenceNumber != 1 {
|
||||
client.Println("drop packet", client.sequenceNumber-1)
|
||||
}
|
||||
client.PreSequenceNumber = client.sequenceNumber
|
||||
if client.BufferRtpPacket.Len() > 4048576 {
|
||||
client.Println("Big Buffer Flush")
|
||||
client.BufferRtpPacket.Truncate(0)
|
||||
client.BufferRtpPacket.Reset()
|
||||
}
|
||||
nalRaw, _ := h264parser.SplitNALUs(content[client.offset:client.end])
|
||||
if len(nalRaw) == 0 || len(nalRaw[0]) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
var retmap []*av.Packet
|
||||
for _, nal := range nalRaw {
|
||||
if client.videoCodec == av.H265 {
|
||||
retmap = client.handleH265Payload(nal, retmap)
|
||||
} else if client.videoCodec == av.H264 {
|
||||
retmap = client.handleH264Payload(content, nal, retmap)
|
||||
}
|
||||
}
|
||||
if len(retmap) > 0 {
|
||||
client.PreVideoTS = client.timestamp
|
||||
return retmap, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (client *RTSPClient) handleH264Payload(content, nal []byte, retmap []*av.Packet) []*av.Packet {
|
||||
naluType := nal[0] & 0x1f
|
||||
switch {
|
||||
case naluType >= 1 && naluType <= 5:
|
||||
retmap = client.appendVideoPacket(retmap, nal, naluType == 5)
|
||||
case naluType == h264parser.NALU_SPS:
|
||||
client.CodecUpdateSPS(nal)
|
||||
case naluType == h264parser.NALU_PPS:
|
||||
client.CodecUpdatePPS(nal)
|
||||
case naluType == 24:
|
||||
packet := nal[1:]
|
||||
for len(packet) >= 2 {
|
||||
size := int(packet[0])<<8 | int(packet[1])
|
||||
if size+2 > len(packet) {
|
||||
break
|
||||
}
|
||||
naluTypefs := packet[2] & 0x1f
|
||||
switch {
|
||||
case naluTypefs >= 1 && naluTypefs <= 5:
|
||||
retmap = client.appendVideoPacket(retmap, packet[2:size+2], naluTypefs == 5)
|
||||
case naluTypefs == h264parser.NALU_SPS:
|
||||
client.CodecUpdateSPS(packet[2 : size+2])
|
||||
case naluTypefs == h264parser.NALU_PPS:
|
||||
client.CodecUpdatePPS(packet[2 : size+2])
|
||||
}
|
||||
packet = packet[size+2:]
|
||||
}
|
||||
case naluType == 28:
|
||||
fuIndicator := content[client.offset]
|
||||
fuHeader := content[client.offset+1]
|
||||
isStart := fuHeader&0x80 != 0
|
||||
isEnd := fuHeader&0x40 != 0
|
||||
if isStart {
|
||||
client.fuStarted = true
|
||||
client.BufferRtpPacket.Truncate(0)
|
||||
client.BufferRtpPacket.Reset()
|
||||
client.BufferRtpPacket.Write([]byte{fuIndicator&0xe0 | fuHeader&0x1f})
|
||||
}
|
||||
if client.fuStarted {
|
||||
client.BufferRtpPacket.Write(content[client.offset+2 : client.end])
|
||||
if isEnd {
|
||||
client.fuStarted = false
|
||||
naluTypef := client.BufferRtpPacket.Bytes()[0] & 0x1f
|
||||
if naluTypef == 7 || naluTypef == 9 {
|
||||
bufered, _ := h264parser.SplitNALUs(append([]byte{0, 0, 0, 1}, client.BufferRtpPacket.Bytes()...))
|
||||
for _, v := range bufered {
|
||||
naluTypefs := v[0] & 0x1f
|
||||
switch {
|
||||
case naluTypefs == 5:
|
||||
client.BufferRtpPacket.Reset()
|
||||
client.BufferRtpPacket.Write(v)
|
||||
naluTypef = 5
|
||||
case naluTypefs == h264parser.NALU_SPS:
|
||||
client.CodecUpdateSPS(v)
|
||||
case naluTypefs == h264parser.NALU_PPS:
|
||||
client.CodecUpdatePPS(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
retmap = client.appendVideoPacket(retmap, client.BufferRtpPacket.Bytes(), naluTypef == 5)
|
||||
}
|
||||
}
|
||||
default:
|
||||
//client.Println("Unsupported NAL Type", naluType)
|
||||
}
|
||||
|
||||
return retmap
|
||||
}
|
||||
|
||||
func (client *RTSPClient) handleH265Payload(nal []byte, retmap []*av.Packet) []*av.Packet {
|
||||
naluType := (nal[0] >> 1) & 0x3f
|
||||
switch naluType {
|
||||
case h265parser.NAL_UNIT_CODED_SLICE_TRAIL_R:
|
||||
retmap = client.appendVideoPacket(retmap, nal, false)
|
||||
case h265parser.NAL_UNIT_VPS:
|
||||
client.CodecUpdateVPS(nal)
|
||||
case h265parser.NAL_UNIT_SPS:
|
||||
client.CodecUpdateSPS(nal)
|
||||
case h265parser.NAL_UNIT_PPS:
|
||||
client.CodecUpdatePPS(nal)
|
||||
case h265parser.NAL_UNIT_UNSPECIFIED_49:
|
||||
se := nal[2] >> 6
|
||||
naluType := nal[2] & 0x3f
|
||||
switch se {
|
||||
case 2:
|
||||
client.BufferRtpPacket.Truncate(0)
|
||||
client.BufferRtpPacket.Reset()
|
||||
client.BufferRtpPacket.Write([]byte{(nal[0] & 0x81) | (naluType << 1), nal[1]})
|
||||
r := make([]byte, 2)
|
||||
r[1] = nal[1]
|
||||
r[0] = (nal[0] & 0x81) | (naluType << 1)
|
||||
client.BufferRtpPacket.Write(nal[3:])
|
||||
case 1:
|
||||
client.BufferRtpPacket.Write(nal[3:])
|
||||
retmap = client.appendVideoPacket(retmap, client.BufferRtpPacket.Bytes(), naluType == h265parser.NAL_UNIT_CODED_SLICE_IDR_W_RADL)
|
||||
default:
|
||||
client.BufferRtpPacket.Write(nal[3:])
|
||||
}
|
||||
default:
|
||||
//client.Println("Unsupported Nal", naluType)
|
||||
}
|
||||
return retmap
|
||||
}
|
||||
|
||||
func (client *RTSPClient) handleAudio(content []byte) ([]*av.Packet, bool) {
|
||||
if client.PreAudioTS == 0 {
|
||||
client.PreAudioTS = client.timestamp
|
||||
}
|
||||
nalRaw, _ := h264parser.SplitNALUs(content[client.offset:client.end])
|
||||
var retmap []*av.Packet
|
||||
for _, nal := range nalRaw {
|
||||
var duration time.Duration
|
||||
switch client.audioCodec {
|
||||
case av.PCM_MULAW, av.PCM_ALAW:
|
||||
duration = time.Duration(len(nal)) * time.Second / time.Duration(client.AudioTimeScale)
|
||||
retmap = client.appendAudioPacket(retmap, nal, duration)
|
||||
case av.OPUS:
|
||||
duration = time.Duration(20) * time.Millisecond
|
||||
retmap = client.appendAudioPacket(retmap, nal, duration)
|
||||
case av.AAC:
|
||||
auHeadersLength := uint16(0) | (uint16(nal[0]) << 8) | uint16(nal[1])
|
||||
auHeadersCount := auHeadersLength >> 4
|
||||
framesPayloadOffset := 2 + int(auHeadersCount)<<1
|
||||
auHeaders := nal[2:framesPayloadOffset]
|
||||
framesPayload := nal[framesPayloadOffset:]
|
||||
for i := 0; i < int(auHeadersCount); i++ {
|
||||
auHeader := uint16(0) | (uint16(auHeaders[0]) << 8) | uint16(auHeaders[1])
|
||||
frameSize := auHeader >> 3
|
||||
frame := framesPayload[:frameSize]
|
||||
auHeaders = auHeaders[2:]
|
||||
framesPayload = framesPayload[frameSize:]
|
||||
if _, _, _, _, err := aacparser.ParseADTSHeader(frame); err == nil {
|
||||
frame = frame[7:]
|
||||
}
|
||||
duration = time.Duration((float32(1024)/float32(client.AudioTimeScale))*1000*1000*1000) * time.Nanosecond
|
||||
retmap = client.appendAudioPacket(retmap, frame, duration)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(retmap) > 0 {
|
||||
client.PreAudioTS = client.timestamp
|
||||
return retmap, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (client *RTSPClient) appendAudioPacket(retmap []*av.Packet, nal []byte, duration time.Duration) []*av.Packet {
|
||||
client.AudioTimeLine += duration
|
||||
return append(retmap, &av.Packet{
|
||||
Data: nal,
|
||||
CompositionTime: time.Duration(1) * time.Millisecond,
|
||||
Duration: duration,
|
||||
Idx: client.audioIDX,
|
||||
IsKeyFrame: false,
|
||||
Time: client.AudioTimeLine,
|
||||
})
|
||||
}
|
||||
|
||||
func (client *RTSPClient) appendVideoPacket(retmap []*av.Packet, nal []byte, isKeyFrame bool) []*av.Packet {
|
||||
return append(retmap, &av.Packet{
|
||||
Data: append(binSize(len(nal)), nal...),
|
||||
CompositionTime: time.Duration(TimeDelay) * time.Millisecond,
|
||||
Idx: client.videoIDX,
|
||||
IsKeyFrame: isKeyFrame,
|
||||
Duration: time.Duration(float32(client.timestamp-client.PreVideoTS)/TimeBaseFactor) * time.Millisecond,
|
||||
Time: time.Duration(client.timestamp/TimeBaseFactor) * time.Millisecond,
|
||||
})
|
||||
}
|
@ -25,6 +25,7 @@ type ProxyConn struct {
|
||||
cseq int
|
||||
session string
|
||||
protocol int
|
||||
in int
|
||||
}
|
||||
|
||||
type Proxy struct {
|
||||
@ -40,7 +41,6 @@ func NewProxyConn(netconn net.Conn) *ProxyConn {
|
||||
conn.writebuf = make([]byte, 4096)
|
||||
conn.readbuf = make([]byte, 4096)
|
||||
conn.session = uuid.New().String()
|
||||
conn.cseq = 1
|
||||
return conn
|
||||
}
|
||||
|
||||
@ -156,6 +156,7 @@ func (self *ProxyConn) prepare() error {
|
||||
return errors.New("no fist cmd")
|
||||
}
|
||||
|
||||
cseq := strings.TrimSpace(stringInBetween(string(self.readbuf[:n]), "CSeq:", "\r\n"))
|
||||
switch fistStringsSlice[0] {
|
||||
case OPTIONS:
|
||||
|
||||
@ -165,45 +166,46 @@ func (self *ProxyConn) prepare() error {
|
||||
if self.URL, err = url.Parse(fistStringsSlice[1]); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := self.netconn.Write([]byte("RTSP/1.0 200 OK\r\nPublic: OPTIONS, DESCRIBE, SETUP, PLAY\r\nSession: " + self.session + "\r\nCSeq: " + strconv.Itoa(self.cseq) + "\r\n\r\n"))
|
||||
_, err := self.netconn.Write([]byte("RTSP/1.0 200 OK\r\nPublic: OPTIONS, DESCRIBE, SETUP, PLAY\r\nSession: " + self.session + "\r\nCSeq: " + cseq + "\r\n\r\n"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
self.options = true
|
||||
|
||||
case SETUP:
|
||||
|
||||
if strings.Contains(string(self.readbuf[:n]), "RTP/AVP/UDP") {
|
||||
_, err := self.netconn.Write([]byte("RTSP/1.0 461 Unsupported transport\r\nCSeq: " + strconv.Itoa(self.cseq) + "\r\nSession: " + self.session + "\r\n\r\n"))
|
||||
_, err := self.netconn.Write([]byte("RTSP/1.0 461 Unsupported transport\r\nCSeq: " + cseq + "\r\nSession: " + self.session + "\r\n\r\n"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
_, err := self.netconn.Write([]byte("RTSP/1.0 200 OK\r\nCSeq: " + strconv.Itoa(self.cseq) + "\r\nSession: " + self.session + "\r\nTransport: RTP/AVP/TCP;unicast;interleaved=0-1\r\n\r\n"))
|
||||
_, err := self.netconn.Write([]byte("RTSP/1.0 200 OK\r\nCSeq: " + cseq + "\r\nSession: " + self.session + "\r\nTransport: RTP/AVP/TCP;unicast;interleaved=" + strconv.Itoa(self.in) + "-" + strconv.Itoa(self.in+1) + "\r\n\r\n"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
self.in = self.in + 2
|
||||
case DESCRIBE:
|
||||
|
||||
buf := "RTSP/1.0 200 OK\r\nContent-Type: application/sdp\r\nSession: " + self.session + "\r\nContent-Length: " + strconv.Itoa(len(self.sdp)) + "\r\nCSeq: " + strconv.Itoa(self.cseq) + "\r\n\r\n"
|
||||
buf := "RTSP/1.0 200 OK\r\nContent-Type: application/sdp\r\nSession: " + self.session + "\r\nContent-Length: " + strconv.Itoa(len(self.sdp)) + "\r\nCSeq: " + cseq + "\r\n\r\n"
|
||||
_, err := self.netconn.Write([]byte(buf + string(self.sdp)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case PLAY:
|
||||
|
||||
_, err := self.netconn.Write([]byte("RTSP/1.0 200 OK\r\nSession: " + self.session + ";timeout=60\r\nCSeq: " + strconv.Itoa(self.cseq) + "\r\n\r\n"))
|
||||
_, err := self.netconn.Write([]byte("RTSP/1.0 200 OK\r\nSession: " + self.session + ";timeout=60\r\nCSeq: " + cseq + "\r\n\r\n"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
self.playing = true
|
||||
case TEARDOWN:
|
||||
self.netconn.Close()
|
||||
return errors.New("exit")
|
||||
|
||||
default:
|
||||
|
||||
return errors.New("metod not found")
|
||||
return errors.New("metod not found " + fistStringsSlice[0])
|
||||
|
||||
}
|
||||
return nil
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -30,7 +30,6 @@ const (
|
||||
LocalCache int = 3
|
||||
)
|
||||
|
||||
//
|
||||
const (
|
||||
StreamTypeH264 = 0x1b
|
||||
StreamTypeH265 = 0x24
|
||||
|
@ -6,11 +6,12 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/format/ts/tsio"
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/mjpeg"
|
||||
"git.r-2.top/kunmeng/vdk/format/ts/tsio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
type Demuxer struct {
|
||||
@ -22,7 +23,7 @@ type Demuxer struct {
|
||||
pmt *tsio.PMT
|
||||
streams []*Stream
|
||||
tshdr []byte
|
||||
|
||||
AnnexB bool
|
||||
stage int
|
||||
}
|
||||
|
||||
@ -118,6 +119,8 @@ func (self *Demuxer) initPMT(payload []byte) (err error) {
|
||||
self.streams = append(self.streams, stream)
|
||||
case tsio.ElementaryStreamTypeAdtsAAC:
|
||||
self.streams = append(self.streams, stream)
|
||||
case tsio.ElementaryStreamTypeAlignmentDescriptor:
|
||||
self.streams = append(self.streams, stream)
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -187,7 +190,7 @@ func (self *Demuxer) readTSPacket() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Stream) addPacket(payload []byte, timedelta time.Duration) {
|
||||
func (self *Stream) addPacket(payload []byte, timedelta time.Duration, fixed time.Duration) {
|
||||
dts := self.dts
|
||||
pts := self.pts
|
||||
|
||||
@ -199,6 +202,8 @@ func (self *Stream) addPacket(payload []byte, timedelta time.Duration) {
|
||||
|
||||
if self.pt > 0 {
|
||||
dur = dts + timedelta - self.pt
|
||||
} else {
|
||||
dur = fixed
|
||||
}
|
||||
|
||||
self.pt = dts + timedelta
|
||||
@ -227,8 +232,16 @@ func (self *Stream) payloadEnd() (n int, err error) {
|
||||
return
|
||||
}
|
||||
self.data = nil
|
||||
|
||||
switch self.streamType {
|
||||
case tsio.ElementaryStreamTypeAlignmentDescriptor:
|
||||
if self.CodecData == nil {
|
||||
self.CodecData = mjpeg.CodecData{}
|
||||
}
|
||||
b := make([]byte, 4+len(payload))
|
||||
pio.PutU32BE(b[0:4], uint32(len(payload)))
|
||||
copy(b[4:], payload)
|
||||
self.addPacket(b, time.Duration(0), 0)
|
||||
n++
|
||||
case tsio.ElementaryStreamTypeAdtsAAC:
|
||||
var config aacparser.MPEG4AudioConfig
|
||||
|
||||
@ -243,7 +256,7 @@ func (self *Stream) payloadEnd() (n int, err error) {
|
||||
return
|
||||
}
|
||||
}
|
||||
self.addPacket(payload[hdrlen:framelen], delta)
|
||||
self.addPacket(payload[hdrlen:framelen], delta, time.Duration(samples)*time.Second/time.Duration(config.SampleRate))
|
||||
n++
|
||||
delta += time.Duration(samples) * time.Second / time.Duration(config.SampleRate)
|
||||
payload = payload[framelen:]
|
||||
@ -252,24 +265,43 @@ func (self *Stream) payloadEnd() (n int, err error) {
|
||||
case tsio.ElementaryStreamTypeH264:
|
||||
nalus, _ := h264parser.SplitNALUs(payload)
|
||||
var sps, pps []byte
|
||||
|
||||
for _, nalu := range nalus {
|
||||
if len(nalu) > 0 {
|
||||
naltype := nalu[0] & 0x1f
|
||||
switch {
|
||||
case naltype == 7:
|
||||
sps = nalu
|
||||
info, err := h264parser.ParseSPS(sps)
|
||||
if err == nil {
|
||||
self.fps = info.FPS
|
||||
}
|
||||
case naltype == 8:
|
||||
pps = nalu
|
||||
case h264parser.IsDataNALU(nalu):
|
||||
// raw nalu to avcc
|
||||
if !self.demuxer.AnnexB {
|
||||
b := make([]byte, 4+len(nalu))
|
||||
pio.PutU32BE(b[0:4], uint32(len(nalu)))
|
||||
copy(b[4:], nalu)
|
||||
self.addPacket(b, time.Duration(0))
|
||||
fps := self.fps
|
||||
if self.fps == 0 {
|
||||
fps = 25
|
||||
}
|
||||
self.addPacket(b, time.Duration(0), (1000*time.Millisecond)/time.Duration(fps))
|
||||
n++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.demuxer.AnnexB {
|
||||
b := make([]byte, 4+len(payload))
|
||||
pio.PutU32BE(b[0:4], uint32(len(payload)))
|
||||
copy(b[4:], payload)
|
||||
self.addPacket(b, time.Duration(0), 0)
|
||||
n++
|
||||
}
|
||||
|
||||
if self.CodecData == nil && len(sps) > 0 && len(pps) > 0 {
|
||||
if self.CodecData, err = h264parser.NewCodecDataFromSPSAndPPS(sps, pps); err != nil {
|
||||
|
@ -3,8 +3,8 @@ package ts
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/av/avutil"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av/avutil"
|
||||
)
|
||||
|
||||
func Handler(h *avutil.RegisterHandler) {
|
||||
|
@ -2,16 +2,17 @@ package ts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h265parser"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/aacparser"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"github.com/deepch/vdk/format/ts/tsio"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/aacparser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/format/ts/tsio"
|
||||
)
|
||||
|
||||
var CodecTypes = []av.CodecType{av.H264, av.AAC}
|
||||
var CodecTypes = []av.CodecType{av.H264, av.H265, av.AAC}
|
||||
|
||||
type Muxer struct {
|
||||
w io.Writer
|
||||
@ -67,11 +68,16 @@ func (self *Muxer) newStream(idx int, codec av.CodecData) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Muxer) writePaddingTSPackets(tsw *tsio.TSWriter) (err error) {
|
||||
for tsw.ContinuityCounter&0xf != 0x0 {
|
||||
if err = tsw.WritePackets(self.w, self.datav[:1], 0, false, true); err != nil {
|
||||
func (self *Muxer) writePaddingTSPackets(streamW *Stream) (err error) {
|
||||
for streamW.tsw.ContinuityCounter&0xf != 0x0 {
|
||||
header := tsio.TSHeader{
|
||||
PID: uint(streamW.pid),
|
||||
ContinuityCounter: streamW.tsw.ContinuityCounter,
|
||||
}
|
||||
if _, err = tsio.WriteTSHeader(self.w, header, 0); err != nil {
|
||||
return
|
||||
}
|
||||
streamW.tsw.ContinuityCounter++
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -79,7 +85,7 @@ func (self *Muxer) writePaddingTSPackets(tsw *tsio.TSWriter) (err error) {
|
||||
func (self *Muxer) WriteTrailer() (err error) {
|
||||
if self.PaddingToMakeCounterCont {
|
||||
for _, stream := range self.streams {
|
||||
if err = self.writePaddingTSPackets(stream.tsw); err != nil {
|
||||
if err = self.writePaddingTSPackets(stream); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -118,6 +124,11 @@ func (self *Muxer) WritePATPMT() (err error) {
|
||||
StreamType: tsio.ElementaryStreamTypeH264,
|
||||
ElementaryPID: stream.pid,
|
||||
})
|
||||
case av.H265:
|
||||
elemStreams = append(elemStreams, tsio.ElementaryStreamInfo{
|
||||
StreamType: tsio.ElementaryStreamTypeH265,
|
||||
ElementaryPID: stream.pid,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,6 +216,36 @@ func (self *Muxer) WritePacket(pkt av.Packet) (err error) {
|
||||
n := tsio.FillPESHeader(self.peshdr, tsio.StreamIdH264, -1, pkt.Time+pkt.CompositionTime, pkt.Time)
|
||||
datav[0] = self.peshdr[:n]
|
||||
|
||||
if err = stream.tsw.WritePackets(self.w, datav, pkt.Time, pkt.IsKeyFrame, false); err != nil {
|
||||
return
|
||||
}
|
||||
case av.H265:
|
||||
codec := stream.CodecData.(h265parser.CodecData)
|
||||
|
||||
nalus := self.nalus[:0]
|
||||
if pkt.IsKeyFrame {
|
||||
nalus = append(nalus, codec.SPS())
|
||||
nalus = append(nalus, codec.PPS())
|
||||
nalus = append(nalus, codec.VPS())
|
||||
}
|
||||
pktnalus, _ := h265parser.SplitNALUs(pkt.Data)
|
||||
for _, nalu := range pktnalus {
|
||||
nalus = append(nalus, nalu)
|
||||
}
|
||||
|
||||
datav := self.datav[:1]
|
||||
for i, nalu := range nalus {
|
||||
if i == 0 {
|
||||
datav = append(datav, h265parser.AUDBytes)
|
||||
} else {
|
||||
datav = append(datav, h265parser.StartCodeBytes)
|
||||
}
|
||||
datav = append(datav, nalu)
|
||||
}
|
||||
|
||||
n := tsio.FillPESHeader(self.peshdr, tsio.StreamIdH264, -1, pkt.Time+pkt.CompositionTime, pkt.Time)
|
||||
datav[0] = self.peshdr[:n]
|
||||
|
||||
if err = stream.tsw.WritePackets(self.w, datav, pkt.Time, pkt.IsKeyFrame, false); err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ package ts
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/format/ts/tsio"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/format/ts/tsio"
|
||||
)
|
||||
|
||||
type Stream struct {
|
||||
@ -19,7 +19,7 @@ type Stream struct {
|
||||
|
||||
tsw *tsio.TSWriter
|
||||
idx int
|
||||
|
||||
fps uint
|
||||
iskeyframe bool
|
||||
pts, dts, pt time.Duration
|
||||
data []byte
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/utils/bits/pio"
|
||||
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -35,6 +35,8 @@ var ErrParsePAT = fmt.Errorf("invalid PAT")
|
||||
const (
|
||||
ElementaryStreamTypeH264 = 0x1B
|
||||
ElementaryStreamTypeAdtsAAC = 0x0F
|
||||
ElementaryStreamTypeAlignmentDescriptor = 0x06
|
||||
ElementaryStreamTypeH265 = 0x24
|
||||
)
|
||||
|
||||
type PATEntry struct {
|
||||
|
@ -10,8 +10,8 @@ import (
|
||||
|
||||
"github.com/pion/webrtc/v2"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
"github.com/pion/webrtc/v2/pkg/media"
|
||||
)
|
||||
|
||||
|
@ -7,9 +7,9 @@ import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/deepch/vdk/codec/h264parser"
|
||||
"git.r-2.top/kunmeng/vdk/codec/h264parser"
|
||||
|
||||
"github.com/deepch/vdk/av"
|
||||
"git.r-2.top/kunmeng/vdk/av"
|
||||
"github.com/pion/interceptor"
|
||||
"github.com/pion/webrtc/v3"
|
||||
"github.com/pion/webrtc/v3/pkg/media"
|
||||
@ -65,6 +65,10 @@ func (element *Muxer) NewPeerConnection(configuration webrtc.Configuration) (*we
|
||||
Credential: element.Options.ICECredential,
|
||||
CredentialType: webrtc.ICECredentialTypePassword,
|
||||
})
|
||||
} else {
|
||||
configuration.ICEServers = append(configuration.ICEServers, webrtc.ICEServer{
|
||||
URLs: []string{"stun:stun.l.google.com:19302"},
|
||||
})
|
||||
}
|
||||
m := &webrtc.MediaEngine{}
|
||||
if err := m.RegisterDefaultCodecs(); err != nil {
|
||||
@ -118,13 +122,22 @@ func (element *Muxer) WriteHeader(streams []av.CodecData, sdp64 string) (string,
|
||||
if i2.Type().IsVideo() {
|
||||
if i2.Type() == av.H264 {
|
||||
track, err = webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{
|
||||
MimeType: "video/h264",
|
||||
}, "pion-rtsp-video", "pion-rtsp-video")
|
||||
MimeType: webrtc.MimeTypeH264,
|
||||
}, "pion-rtsp-video", "pion-video")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, err = peerConnection.AddTrack(track); err != nil {
|
||||
if rtpSender, err := peerConnection.AddTrack(track); err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
go func() {
|
||||
rtcpBuf := make([]byte, 1500)
|
||||
for {
|
||||
if _, _, rtcpErr := rtpSender.Read(rtcpBuf); rtcpErr != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
} else if i2.Type().IsAudio() {
|
||||
@ -148,8 +161,17 @@ func (element *Muxer) WriteHeader(streams []av.CodecData, sdp64 string) (string,
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, err = peerConnection.AddTrack(track); err != nil {
|
||||
if rtpSender, err := peerConnection.AddTrack(track); err != nil {
|
||||
return "", err
|
||||
} else {
|
||||
go func() {
|
||||
rtcpBuf := make([]byte, 1500)
|
||||
for {
|
||||
if _, _, rtcpErr := rtpSender.Read(rtcpBuf); rtcpErr != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
element.streams[int8(i)] = &Stream{track: track, codec: i2}
|
||||
@ -225,8 +247,7 @@ func (element *Muxer) WritePacket(pkt av.Packet) (err error) {
|
||||
if naltype == 5 {
|
||||
codec := tmp.codec.(h264parser.CodecData)
|
||||
err = tmp.track.WriteSample(media.Sample{Data: append([]byte{0, 0, 0, 1}, bytes.Join([][]byte{codec.SPS(), codec.PPS(), nalu}, []byte{0, 0, 0, 1})...), Duration: pkt.Duration})
|
||||
|
||||
} else if naltype == 1 {
|
||||
} else {
|
||||
err = tmp.track.WriteSample(media.Sample{Data: append([]byte{0, 0, 0, 1}, nalu...), Duration: pkt.Duration})
|
||||
}
|
||||
if err != nil {
|
||||
|
55
go.mod
55
go.mod
@ -1,11 +1,56 @@
|
||||
module github.com/deepch/vdk
|
||||
module git.r-2.top/kunmeng/vdk
|
||||
|
||||
go 1.15
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/gobwas/ws v1.3.1
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/pion/interceptor v0.1.8
|
||||
github.com/pion/interceptor v0.1.17
|
||||
github.com/pion/webrtc/v2 v2.2.26
|
||||
github.com/pion/webrtc/v3 v3.1.24
|
||||
github.com/quadrifoglio/go-mkv v0.0.0-20180620161916-e7a1fc70199c // indirect
|
||||
github.com/pion/webrtc/v3 v3.2.12
|
||||
github.com/shirou/gopsutil/v3 v3.24.5
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20230309165930-d61513b1440d // indirect
|
||||
github.com/lucas-clemente/quic-go v0.31.1 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.4 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.2 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.9.0 // indirect
|
||||
github.com/pion/datachannel v1.5.5 // indirect
|
||||
github.com/pion/dtls/v2 v2.2.7 // indirect
|
||||
github.com/pion/ice v0.7.18 // indirect
|
||||
github.com/pion/ice/v2 v2.3.9 // indirect
|
||||
github.com/pion/logging v0.2.2 // indirect
|
||||
github.com/pion/mdns v0.0.7 // indirect
|
||||
github.com/pion/quic v0.1.4 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/rtcp v1.2.10 // indirect
|
||||
github.com/pion/rtp v1.7.13 // indirect
|
||||
github.com/pion/sctp v1.8.7 // indirect
|
||||
github.com/pion/sdp/v2 v2.4.0 // indirect
|
||||
github.com/pion/sdp/v3 v3.0.6 // indirect
|
||||
github.com/pion/srtp v1.5.2 // indirect
|
||||
github.com/pion/srtp/v2 v2.0.15 // indirect
|
||||
github.com/pion/stun v0.6.1 // indirect
|
||||
github.com/pion/transport v0.14.1 // indirect
|
||||
github.com/pion/transport/v2 v2.2.1 // indirect
|
||||
github.com/pion/turn/v2 v2.1.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/stretchr/testify v1.9.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
golang.org/x/crypto v0.10.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 // indirect
|
||||
golang.org/x/mod v0.9.0 // indirect
|
||||
golang.org/x/net v0.11.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
447
go.sum
447
go.sum
@ -1,197 +1,301 @@
|
||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
|
||||
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
|
||||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
|
||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU=
|
||||
github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20230309165930-d61513b1440d h1:um9/pc7tKMINFfP1eE7Wv6PRGXlcCSJkVajF7KJw3uQ=
|
||||
github.com/google/pprof v0.0.0-20230309165930-d61513b1440d/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lucas-clemente/quic-go v0.7.1-0.20190401152353-907071221cf9 h1:tbuodUh2vuhOVZAdW3NEUvosFHUMJwUNl7jk/VSEiwc=
|
||||
github.com/lucas-clemente/quic-go v0.7.1-0.20190401152353-907071221cf9/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw=
|
||||
github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA=
|
||||
github.com/lucas-clemente/quic-go v0.18.0/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg=
|
||||
github.com/lucas-clemente/quic-go v0.31.1 h1:O8Od7hfioqq0PMYHDyBkxU2aA7iZ2W9pjbrWuja2YR4=
|
||||
github.com/lucas-clemente/quic-go v0.31.1/go.mod h1:0wFbizLgYzqHqtlyxyCaJKlE7bYgE6JQ+54TLd/Dq2g=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/marten-seemann/qpack v0.2.0/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
|
||||
github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
|
||||
github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs=
|
||||
github.com/marten-seemann/qtls-go1-15 v0.1.0/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.4 h1:ogomB+lWV3Vmwiu6RTwDVTMGx+9j7SEi98e8QB35Its=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.4/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.2 h1:ZevAEqKXH0bZmoOBPiqX2h5rhQ7cbZi+X+rlq2JUbCE=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.2/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.16.1 h1:foqVmeWDD6yYpK+Yz3fHyNIxFYNxswxqNFjSKe+vI54=
|
||||
github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.9.0 h1:Tugw2BKlNHTMfG+CheOITkYvk4LAh6MFOvikhGVnhE8=
|
||||
github.com/onsi/ginkgo/v2 v2.9.0/go.mod h1:4xkjoL/tZv4SMWeww56BU5kAt19mVB47gTWxmrTcxyk=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.11.0 h1:+CqWgvj0OZycCaqclBD1pxKHAU+tOkHmQIWvDHq2aug=
|
||||
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/pion/datachannel v1.4.21 h1:3ZvhNyfmxsAqltQrApLPQMhSFNA+aT87RqyCq4OXmf0=
|
||||
github.com/onsi/gomega v1.27.1 h1:rfztXRbg6nv/5f+Raen9RcGoSecHIFgBBLQK3Wdj754=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/pion/datachannel v1.4.21/go.mod h1:oiNyP4gHx2DIwRzX/MFyH0Rz/Gz05OgBlayAI2hAWjg=
|
||||
github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E=
|
||||
github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ=
|
||||
github.com/pion/datachannel v1.5.5 h1:10ef4kwdjije+M9d7Xm9im2Y3O6A6ccQb0zcqZcJew8=
|
||||
github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0=
|
||||
github.com/pion/dtls/v2 v2.0.1/go.mod h1:uMQkz2W0cSqY00xav7WByQ4Hb+18xeQh2oH2fRezr5U=
|
||||
github.com/pion/dtls/v2 v2.0.2/go.mod h1:27PEO3MDdaCfo21heT59/vsdmZc0zMt9wQPcSlLu/1I=
|
||||
github.com/pion/dtls/v2 v2.0.9 h1:7Ow+V++YSZQMYzggI0P9vLJz/hUFcffsfGMfT/Qy+u8=
|
||||
github.com/pion/dtls/v2 v2.0.9/go.mod h1:O0Wr7si/Zj5/EBFlDzDd6UtVxx25CE1r7XM7BQKYQho=
|
||||
github.com/pion/dtls/v2 v2.0.13/go.mod h1:OaE7eTM+ppaUhJ99OTO4aHl9uY6vPrT1gPY27uNTxRY=
|
||||
github.com/pion/dtls/v2 v2.1.0 h1:g6gtKVNLp6URDkv9OijFJl16kqGHzVzZG+Fa4A38GTY=
|
||||
github.com/pion/dtls/v2 v2.1.0/go.mod h1:qG3gA7ZPZemBqpEFqRKyURYdKEwFZQCGb7gv9T3ON3Y=
|
||||
github.com/pion/dtls/v2 v2.1.2/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus=
|
||||
github.com/pion/dtls/v2 v2.1.3 h1:3UF7udADqous+M2R5Uo2q/YaP4EzUoWKdfX2oscCUio=
|
||||
github.com/pion/dtls/v2 v2.1.3/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus=
|
||||
github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
|
||||
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
|
||||
github.com/pion/ice v0.7.18 h1:KbAWlzWRUdX9SmehBh3gYpIFsirjhSQsCw6K2MjYMK0=
|
||||
github.com/pion/ice v0.7.18/go.mod h1:+Bvnm3nYC6Nnp7VV6glUkuOfToB/AtMRZpOU8ihuf4c=
|
||||
github.com/pion/ice/v2 v2.1.7 h1:FjgDfUNrVYTxQabJrkBX6ld12tvYbgzHenqPh3PJF6E=
|
||||
github.com/pion/ice/v2 v2.1.7/go.mod h1:kV4EODVD5ux2z8XncbLHIOtcXKtYXVgLVCeVqnpoeP0=
|
||||
github.com/pion/ice/v2 v2.1.12 h1:ZDBuZz+fEI7iDifZCYFVzI4p0Foy0YhdSSZ87ZtRcRE=
|
||||
github.com/pion/ice/v2 v2.1.12/go.mod h1:ovgYHUmwYLlRvcCLI67PnQ5YGe+upXZbGgllBDG/ktU=
|
||||
github.com/pion/ice/v2 v2.1.18 h1:mDzd+iPKJmU30p4Kb+RPjK9olORLqJmQdiTUnVba50g=
|
||||
github.com/pion/ice/v2 v2.1.18/go.mod h1:9jDr0iIUg8P6+0Jq8QJ/eFSkX3JnsPd293TjCdkfpTs=
|
||||
github.com/pion/ice/v2 v2.2.1 h1:R3MeuJZpU1ty3diPqpD5OxaxcZ15eprAc+EtUiSoFxg=
|
||||
github.com/pion/ice/v2 v2.2.1/go.mod h1:Op8jlPtjeiycsXh93Cs4jK82C9j/kh7vef6ztIOvtIQ=
|
||||
github.com/pion/interceptor v0.0.12 h1:eC1iVneBIAQJEfaNAfDqAncJWhMDAnaXPRCJsltdokE=
|
||||
github.com/pion/interceptor v0.0.12/go.mod h1:qzeuWuD/ZXvPqOnxNcnhWfkCZ2e1kwwslicyyPnhoK4=
|
||||
github.com/pion/interceptor v0.1.0 h1:SlXKaDlEvSl7cr4j8fJykzVz4UdH+7UDtcvx+u01wLU=
|
||||
github.com/pion/interceptor v0.1.0/go.mod h1:j5NIl3tJJPB3u8+Z2Xz8MZs/VV6rc+If9mXEKNuFmEM=
|
||||
github.com/pion/interceptor v0.1.6 h1:ZTXN9fApUDmFqifG64g+ar57XY7vlnXUs7/0DjHVtLo=
|
||||
github.com/pion/interceptor v0.1.6/go.mod h1:Lh3JSl/cbJ2wP8I3ccrjh1K/deRGRn3UlSPuOTiHb6U=
|
||||
github.com/pion/interceptor v0.1.7/go.mod h1:Lh3JSl/cbJ2wP8I3ccrjh1K/deRGRn3UlSPuOTiHb6U=
|
||||
github.com/pion/interceptor v0.1.8 h1:5K27KMw8enTB1jVDFrjadK8sZjI5JbPJ91OVfiih5fE=
|
||||
github.com/pion/interceptor v0.1.8/go.mod h1:Lh3JSl/cbJ2wP8I3ccrjh1K/deRGRn3UlSPuOTiHb6U=
|
||||
github.com/pion/ice/v2 v2.3.9 h1:7yZpHf3PhPxJGT4JkMj1Y8Rl5cQ6fB709iz99aeMd/U=
|
||||
github.com/pion/ice/v2 v2.3.9/go.mod h1:lT3kv5uUIlHfXHU/ZRD7uKD/ufM202+eTa3C/umgGf4=
|
||||
github.com/pion/interceptor v0.1.17 h1:prJtgwFh/gB8zMqGZoOgJPHivOwVAp61i2aG61Du/1w=
|
||||
github.com/pion/interceptor v0.1.17/go.mod h1:SY8kpmfVBvrbUzvj2bsXz7OJt5JvmVNZ+4Kjq7FcwrI=
|
||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
|
||||
github.com/pion/mdns v0.0.4/go.mod h1:R1sL0p50l42S5lJs91oNdUL58nm0QHrhxnSegr++qC0=
|
||||
github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw=
|
||||
github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g=
|
||||
github.com/pion/quic v0.1.1 h1:D951FV+TOqI9A0rTF7tHx0Loooqz+nyzjEyj8o3PuMA=
|
||||
github.com/pion/mdns v0.0.7 h1:P0UB4Sr6xDWEox0kTVxF0LmQihtCbSAdW0H2nEgkA3U=
|
||||
github.com/pion/mdns v0.0.7/go.mod h1:4iP2UbeFhLI/vWju/bw6ZfwjJzk0z8DNValjGxR/dD8=
|
||||
github.com/pion/quic v0.1.1/go.mod h1:zEU51v7ru8Mp4AUBJvj6psrSth5eEFNnVQK5K48oV3k=
|
||||
github.com/pion/quic v0.1.4 h1:bNz9sCJjlM3GqMdq7Fne57FiWfdyiJ++yHVbuqeoD3Y=
|
||||
github.com/pion/quic v0.1.4/go.mod h1:dBhNvkLoQqRwfi6h3Vqj3IcPLgiW7rkZxBbRdp7Vzvk=
|
||||
github.com/pion/randutil v0.0.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||
github.com/pion/rtcp v1.2.3/go.mod h1:zGhIv0RPRF0Z1Wiij22pUt5W/c9fevqSzT4jje/oK7I=
|
||||
github.com/pion/rtcp v1.2.6 h1:1zvwBbyd0TeEuuWftrd/4d++m+/kZSeiguxU61LFWpo=
|
||||
github.com/pion/rtcp v1.2.6/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
|
||||
github.com/pion/rtcp v1.2.8 h1:Cys8X6r0xxU65ESTmXkqr8eU1Q1Wx+lNkoZCUH4zD7E=
|
||||
github.com/pion/rtcp v1.2.8/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
|
||||
github.com/pion/rtcp v1.2.9 h1:1ujStwg++IOLIEoOiIQ2s+qBuJ1VN81KW+9pMPsif+U=
|
||||
github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
|
||||
github.com/pion/rtcp v1.2.4/go.mod h1:52rMNPWFsjr39z9B9MhnkqhPLoeHTv1aN63o/42bWE0=
|
||||
github.com/pion/rtcp v1.2.10 h1:nkr3uj+8Sp97zyItdN60tE/S6vk4al5CPRR6Gejsdjc=
|
||||
github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I=
|
||||
github.com/pion/rtp v1.6.0/go.mod h1:QgfogHsMBVE/RFNno467U/KBqfUywEH+HK+0rtnwsdI=
|
||||
github.com/pion/rtp v1.6.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
||||
github.com/pion/rtp v1.6.5 h1:o2cZf8OascA5HF/b0PAbTxRKvOWxTQxWYt7SlToxFGI=
|
||||
github.com/pion/rtp v1.6.5/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
||||
github.com/pion/rtp v1.7.0/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
||||
github.com/pion/rtp v1.7.2 h1:HCDKDCixh7PVjkQTsqHAbk1lg+bx059EHxcnyl42dYs=
|
||||
github.com/pion/rtp v1.7.2/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
||||
github.com/pion/rtp v1.7.4 h1:4dMbjb1SuynU5OpA3kz1zHK+u+eOCQjW3MAeVHf1ODA=
|
||||
github.com/pion/rtp v1.7.4/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
||||
github.com/pion/rtp v1.6.1/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
||||
github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA=
|
||||
github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
|
||||
github.com/pion/sctp v1.7.10/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
|
||||
github.com/pion/sctp v1.7.12 h1:GsatLufywVruXbZZT1CKg+Jr8ZTkwiPnmUC/oO9+uuY=
|
||||
github.com/pion/sctp v1.7.12/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
|
||||
github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
|
||||
github.com/pion/sctp v1.8.2 h1:yBBCIrUMJ4yFICL3RIvR4eh/H2BTTvlligmSTy+3kiA=
|
||||
github.com/pion/sctp v1.8.2/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s=
|
||||
github.com/pion/sctp v1.8.5/go.mod h1:SUFFfDpViyKejTAdwD1d/HQsCu+V/40cCs2nZIvC3s0=
|
||||
github.com/pion/sctp v1.8.7 h1:JnABvFakZueGAn4KU/4PSKg+GWbF6QWbKTWZOSGJjXw=
|
||||
github.com/pion/sctp v1.8.7/go.mod h1:g1Ul+ARqZq5JEmoFy87Q/4CePtKnTJ1QCL9dBBdN6AU=
|
||||
github.com/pion/sdp/v2 v2.4.0 h1:luUtaETR5x2KNNpvEMv/r4Y+/kzImzbz4Lm1z8eQNQI=
|
||||
github.com/pion/sdp/v2 v2.4.0/go.mod h1:L2LxrOpSTJbAns244vfPChbciR/ReU1KWfG04OpkR7E=
|
||||
github.com/pion/sdp/v3 v3.0.4 h1:2Kf+dgrzJflNCSw3TV5v2VLeI0s/qkzy2r5jlR0wzf8=
|
||||
github.com/pion/sdp/v3 v3.0.4/go.mod h1:bNiSknmJE0HYBprTHXKPQ3+JjacTv5uap92ueJZKsRk=
|
||||
github.com/pion/srtp v1.5.1 h1:9Q3jAfslYZBt+C69SI/ZcONJh9049JUHZWYRRf5KEKw=
|
||||
github.com/pion/sdp/v3 v3.0.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw=
|
||||
github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw=
|
||||
github.com/pion/srtp v1.5.1/go.mod h1:B+QgX5xPeQTNc1CJStJPHzOlHK66ViMDWTT0HZTCkcA=
|
||||
github.com/pion/srtp/v2 v2.0.2 h1:664iGzVmaY7KYS5M0gleY0DscRo9ReDfTxQrq4UgGoU=
|
||||
github.com/pion/srtp/v2 v2.0.2/go.mod h1:VEyLv4CuxrwGY8cxM+Ng3bmVy8ckz/1t6A0q/msKOw0=
|
||||
github.com/pion/srtp/v2 v2.0.5 h1:ks3wcTvIUE/GHndO3FAvROQ9opy0uLELpwHJaQ1yqhQ=
|
||||
github.com/pion/srtp/v2 v2.0.5/go.mod h1:8k6AJlal740mrZ6WYxc4Dg6qDqqhxoRG2GSjlUhDF0A=
|
||||
github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg=
|
||||
github.com/pion/srtp v1.5.2 h1:25DmvH+fqKZDqvX64vTwnycVwL9ooJxHF/gkX16bDBY=
|
||||
github.com/pion/srtp v1.5.2/go.mod h1:NiBff/MSxUwMUwx/fRNyD/xGE+dVvf8BOCeXhjCXZ9U=
|
||||
github.com/pion/srtp/v2 v2.0.15 h1:+tqRtXGsGwHC0G0IUIAzRmdkHvriF79IHVfZGfHrQoA=
|
||||
github.com/pion/srtp/v2 v2.0.15/go.mod h1:b/pQOlDrbB0HEH5EUAQXzSYxikFbNcNuKmF8tM0hCtw=
|
||||
github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA=
|
||||
github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4=
|
||||
github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
|
||||
github.com/pion/transport v0.6.0/go.mod h1:iWZ07doqOosSLMhZ+FXUTq+TamDoXSllxpbGcfkCmbE=
|
||||
github.com/pion/transport v0.8.10/go.mod h1:tBmha/UCjpum5hqTWhfAEs3CO4/tHSg0MYRhSzR+CZ8=
|
||||
github.com/pion/transport v0.10.0/go.mod h1:BnHnUipd0rZQyTVB2SBGojFHT9CBt5C5TcsJSQGkvSE=
|
||||
github.com/pion/transport v0.10.1/go.mod h1:PBis1stIILMiis0PewDw91WJeLJkyIMcEk+DwKOzf4A=
|
||||
github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
|
||||
github.com/pion/transport v0.12.3 h1:vdBfvfU/0Wq8kd2yhUMSDB/x+O4Z9MYVl2fJ5BT4JZw=
|
||||
github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A=
|
||||
github.com/pion/transport v0.13.0 h1:KWTA5ZrQogizzYwPEciGtHPLwpAjE91FgXnyu+Hv2uY=
|
||||
github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g=
|
||||
github.com/pion/transport v0.14.1 h1:XSM6olwW+o8J4SCmOBb/BpwZypkHeyM0PGFCxNQBr40=
|
||||
github.com/pion/transport v0.14.1/go.mod h1:4tGmbk00NeYA3rUa9+n+dzCCoKkcy3YlYb99Jn2fNnI=
|
||||
github.com/pion/transport/v2 v2.0.0/go.mod h1:HS2MEBJTwD+1ZI2eSXSvHJx/HnzQqRy2/LXxt6eVMHc=
|
||||
github.com/pion/transport/v2 v2.1.0/go.mod h1:AdSw4YBZVDkZm8fpoz+fclXyQwANWmZAlDuQdctTThQ=
|
||||
github.com/pion/transport/v2 v2.2.0/go.mod h1:AdSw4YBZVDkZm8fpoz+fclXyQwANWmZAlDuQdctTThQ=
|
||||
github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c=
|
||||
github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g=
|
||||
github.com/pion/turn/v2 v2.0.4/go.mod h1:1812p4DcGVbYVBTiraUmP50XoKye++AMkbfp+N27mog=
|
||||
github.com/pion/turn/v2 v2.0.5 h1:iwMHqDfPEDEOFzwWKT56eFmh6DYC6o/+xnLAEzgISbA=
|
||||
github.com/pion/turn/v2 v2.0.5/go.mod h1:APg43CFyt/14Uy7heYUOGWdkem/Wu4PhCO/bjyrTqMw=
|
||||
github.com/pion/turn/v2 v2.0.6 h1:AsXjSPR6Im15DMTB39NlfdTY9BQfieANPBjdg/aVNwY=
|
||||
github.com/pion/turn/v2 v2.0.6/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw=
|
||||
github.com/pion/turn/v2 v2.0.8 h1:KEstL92OUN3k5k8qxsXHpr7WWfrdp7iJZHx99ud8muw=
|
||||
github.com/pion/turn/v2 v2.0.8/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw=
|
||||
github.com/pion/turn/v2 v2.1.2 h1:wj0cAoGKltaZ790XEGW9HwoUewqjliwmhtxCuB2ApyM=
|
||||
github.com/pion/turn/v2 v2.1.2/go.mod h1:1kjnPkBcex3dhCU2Am+AAmxDcGhLX3WnMfmkNpvSTQU=
|
||||
github.com/pion/udp v0.1.0/go.mod h1:BPELIjbwE9PRbd/zxI/KYBnbo7B6+oA6YuEaNE8lths=
|
||||
github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
|
||||
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
|
||||
github.com/pion/webrtc/v2 v2.2.26 h1:01hWE26pL3LgqfxvQ1fr6O4ZtyRFFJmQEZK39pHWfFc=
|
||||
github.com/pion/webrtc/v2 v2.2.26/go.mod h1:XMZbZRNHyPDe1gzTIHFcQu02283YO45CbiwFgKvXnmc=
|
||||
github.com/pion/webrtc/v3 v3.0.29 h1:pVs6mYjbbYvC8pMsztayEz35DnUEFLPswsicGXaQjxo=
|
||||
github.com/pion/webrtc/v3 v3.0.29/go.mod h1:XFQeLYBf++bWWA0sJqh6zF1ouWluosxwTOMOoTZGaD0=
|
||||
github.com/pion/webrtc/v3 v3.1.1 h1:UA4qU+zoAAlUkl0J7ek/YnV3e0orvE8V667imvmnAoo=
|
||||
github.com/pion/webrtc/v3 v3.1.1/go.mod h1:t51XSam1k56eYLuO1Ubxjs3pDBfGYxkGBFhYf55Mn/s=
|
||||
github.com/pion/webrtc/v3 v3.1.17 h1:6V4Yf5wnvJZKs86401EcpsKmB5Px5pfF1ICXdPIRsC0=
|
||||
github.com/pion/webrtc/v3 v3.1.17/go.mod h1:kHunUx6HPCbCvGy/HdWQNwtT9LJ2XMS/sBmLwB1A4rs=
|
||||
github.com/pion/webrtc/v3 v3.1.24 h1:s9PuwisrgHe1FTqfwK4p3T7rXtAHaUNhycbdMjADT28=
|
||||
github.com/pion/webrtc/v3 v3.1.24/go.mod h1:mO/yv7fBN3Lp7YNlnYcTj1jtpvNvssJG+7eh6itZ4xM=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pion/webrtc/v3 v3.2.12 h1:pVqz5NdtTqyhKIhMcXR8bPp709kCf9blyAhDjoVRLvA=
|
||||
github.com/pion/webrtc/v3 v3.2.12/go.mod h1:/Oz6K95CGWaN+3No+Z0NYvgOPOr3aY8UyTlMm/dec3A=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quadrifoglio/go-mkv v0.0.0-20180620161916-e7a1fc70199c h1:Nu1I2o5Lk5nvn2RChPOJ1MzTXKZoHiy665a5aANHssQ=
|
||||
github.com/quadrifoglio/go-mkv v0.0.0-20180620161916-e7a1fc70199c/go.mod h1:Mtv+LuzkLR5r7fwBlvqI/N/5d4nOaH/7fpgQFXwxnFk=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
|
||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
|
||||
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
|
||||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
|
||||
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
|
||||
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
|
||||
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
|
||||
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
|
||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
|
||||
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
|
||||
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
|
||||
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
|
||||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
||||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
|
||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE=
|
||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0 h1:LGJsf5LRplCck6jUCH3dBL2dmycNruWNF5xugkSlfXw=
|
||||
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@ -201,82 +305,159 @@ golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210420210106-798c2154c571 h1:Q6Bg8xzKzpFPU4Oi1sBnBTHBwlMsLeEXpu4hYBY8rAg=
|
||||
golang.org/x/net v0.0.0-20210420210106-798c2154c571/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw=
|
||||
golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe h1:WdX7u8s3yOigWAhHEaDl8r9G+4XwFQEQFtBMYyN+kXQ=
|
||||
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
|
Loading…
Reference in New Issue
Block a user