Compare commits

..

1 Commits

Author SHA1 Message Date
Renovate Bot
ce33de8ae9
Update github/codeql-action action to v2 2022-04-25 14:37:44 +00:00
90 changed files with 788 additions and 2076 deletions

View File

@ -43,7 +43,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@ -54,7 +54,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@ -68,4 +68,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2

View File

@ -121,7 +121,6 @@ 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)
@ -191,7 +190,7 @@ const avCodecTypeMagic = 233333
// CodecData is some important bytes for initializing audio/video decoder,
// can be converted to VideoCodecData or AudioCodecData using:
//
// codecdata.(AudioCodecData) or codecdata.(VideoCodecData)
// codecdata.(AudioCodecData) or codecdata.(VideoCodecData)
//
// for H264, CodecData is AVCDecoderConfigure bytes, includes SPS/PPS.
type CodecData interface {
@ -255,8 +254,6 @@ 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.

View File

@ -5,10 +5,10 @@ import (
"io"
"time"
"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"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/av/avutil"
"github.com/deepch/vdk/av/pktque"
"github.com/deepch/vdk/av/transcode"
)
var Debug bool

View File

@ -9,9 +9,7 @@ import (
"path"
"strings"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/codec/aacparser"
"git.r-2.top/kunmeng/vdk/codec/h264parser"
"github.com/deepch/vdk/av"
)
type HandlerDemuxer struct {
@ -312,31 +310,3 @@ 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
}

View File

@ -1,7 +1,7 @@
package pktque
import (
"git.r-2.top/kunmeng/vdk/av"
"github.com/deepch/vdk/av"
)
type Buf struct {

View File

@ -4,7 +4,7 @@ package pktque
import (
"time"
"git.r-2.top/kunmeng/vdk/av"
"github.com/deepch/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,20 +170,6 @@ 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

View File

@ -6,8 +6,8 @@ import (
"sync"
"time"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/av/pktque"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/av/pktque"
)
// time

View File

@ -5,8 +5,8 @@ import (
"fmt"
"time"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/av/pktque"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/av/pktque"
)
var Debug bool

View File

@ -17,9 +17,9 @@ import (
"time"
"unsafe"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/av/avutil"
"git.r-2.top/kunmeng/vdk/codec/aacparser"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/av/avutil"
"github.com/deepch/vdk/codec/aacparser"
)
const debug = false

View File

@ -20,8 +20,8 @@ import (
"runtime"
"unsafe"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/codec/h264parser"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/codec/h264parser"
)
type VideoDecoder struct {

View File

@ -6,8 +6,8 @@ import (
"io"
"time"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/utils/bits"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/utils/bits"
)
// copied from libavcodec/mpeg4audio.h

View File

@ -3,8 +3,8 @@ package codec
import (
"time"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/codec/fake"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/codec/fake"
)
type OpusCodecData struct {

View File

@ -1,7 +1,7 @@
package fake
import (
"git.r-2.top/kunmeng/vdk/av"
"github.com/deepch/vdk/av"
)
type CodecData struct {

View File

@ -5,11 +5,10 @@ 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 (
@ -665,19 +664,11 @@ func (self CodecData) AVCDecoderConfRecordBytes() []byte {
}
func (self CodecData) SPS() []byte {
if len(self.RecordInfo.SPS) > 0 {
return self.RecordInfo.SPS[0]
}
return []byte{0}
return self.RecordInfo.SPS[0]
}
func (self CodecData) PPS() []byte {
if len(self.RecordInfo.PPS) > 0 {
return self.RecordInfo.PPS[0]
}
return []byte{0}
return self.RecordInfo.PPS[0]
}
func (self CodecData) Width() int {

View File

@ -4,11 +4,10 @@ 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 {
@ -463,8 +462,7 @@ 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 "hev1.1.6.L120.90"
return fmt.Sprintf("hvc1.%02X%02X%02X", self.RecordInfo.AVCProfileIndication, self.RecordInfo.ProfileCompatibility, self.RecordInfo.AVCLevelIndication)
}
func (self CodecData) Bandwidth() string {
@ -531,7 +529,7 @@ type AVCDecoderConfRecord struct {
var ErrDecconfInvalid = fmt.Errorf("h265parser: AVCDecoderConfRecord invalid")
func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) {
if len(b) < 30 {
if len(b) < 7 {
err = ErrDecconfInvalid
return
}
@ -539,36 +537,8 @@ func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) {
self.ProfileCompatibility = b[2]
self.AVCLevelIndication = b[3]
self.LengthSizeMinusOne = b[4] & 0x03
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++
spscount := int(b[5] & 0x1f)
n += 6
for i := 0; i < spscount; i++ {
if len(b) < n+2 {
err = ErrDecconfInvalid
@ -585,8 +555,10 @@ func (self *AVCDecoderConfRecord) Unmarshal(b []byte) (n int, err error) {
n += spslen
}
n++
n++
if len(b) < n+1 {
err = ErrDecconfInvalid
return
}
ppscount := int(b[n])
n++
@ -606,6 +578,25 @@ 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
}

View File

@ -1,10 +0,0 @@
package mjpeg
import "git.r-2.top/kunmeng/vdk/av"
type CodecData struct {
}
func (d CodecData) Type() av.CodecType {
return av.MJPEG
}

View File

@ -4,7 +4,7 @@ import (
"errors"
"time"
"git.r-2.top/kunmeng/vdk/av"
"github.com/deepch/vdk/av"
)
type CodecData struct {

View File

@ -1,25 +0,0 @@
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++
}
}

View File

@ -1,71 +0,0 @@
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
}
}
}
}

View File

@ -6,9 +6,9 @@ import (
"io"
"time"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/av/avutil"
"git.r-2.top/kunmeng/vdk/codec/aacparser"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/av/avutil"
"github.com/deepch/vdk/codec/aacparser"
)
type Muxer struct {

View File

@ -12,9 +12,9 @@ import (
"strings"
"time"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/codec"
"git.r-2.top/kunmeng/vdk/codec/h264parser"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/codec"
"github.com/deepch/vdk/codec/h264parser"
)
const (
@ -47,7 +47,7 @@ type ClientOptions struct {
DisableAudio bool
}
// Dial func
//Dial func
func Dial(options ClientOptions) (*Client, error) {
client := &Client{
Signals: make(chan int, 100),
@ -78,13 +78,13 @@ func Dial(options ClientOptions) (*Client, error) {
return client, nil
}
// Close func
//Close func
func (client *Client) Close() error {
err := client.conn.Close()
return err
}
// SetKeepAlive func
//SetKeepAlive func
func (client *Client) SetKeepAlive() error {
body, err := json.Marshal(map[string]string{
"Name": "KeepAlive",
@ -100,7 +100,7 @@ func (client *Client) SetKeepAlive() error {
return nil
}
// Monitor func
//Monitor func
func (client *Client) Monitor() {
defer func() {
client.Signals <- SignalStreamStop
@ -321,7 +321,7 @@ func (client *Client) Login() error {
return nil
}
// Command func
//Command func
func (client *Client) Command(command requestCode, data interface{}) (*Payload, []byte, error) {
params, err := json.Marshal(map[string]interface{}{
"Name": requestCodes[command],
@ -339,7 +339,7 @@ func (client *Client) Command(command requestCode, data interface{}) (*Payload,
return resp, body, err
}
// send func
//send func
func (client *Client) send(msgID requestCode, data []byte) error {
var buf bytes.Buffer
if err := binary.Write(&buf, binary.LittleEndian, Payload{
@ -372,7 +372,7 @@ func (client *Client) send(msgID requestCode, data []byte) error {
return nil
}
// recvSize func
//recvSize func
func (client *Client) recvSize(buffer *bytes.Buffer, size uint32) ([]byte, error) {
all := uint32(0)
for {
@ -391,7 +391,7 @@ func (client *Client) recvSize(buffer *bytes.Buffer, size uint32) ([]byte, error
return nil, nil
}
// recv func
//recv func
func (client *Client) recv(text bool) (*Payload, []byte, error) {
var p Payload
var b = make([]byte, 20)
@ -422,7 +422,7 @@ func (client *Client) recv(text bool) (*Payload, []byte, error) {
return &p, body, nil
}
// parseURL func
//parseURL func
func (client *Client) parseURL(rawURL string) error {
l, err := url.Parse(rawURL)
if err != nil {

View File

@ -5,15 +5,14 @@ import (
"fmt"
"io"
"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"
"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"
)
var MaxProbePacketCount = 20
@ -29,8 +28,6 @@ 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())
@ -90,12 +87,10 @@ func (self *Prober) PushTag(tag flvio.Tag, timestamp int32) (err error) {
switch tag.AVCPacketType {
case flvio.AVC_SEQHDR:
if !self.GotVideo {
var stream av.CodecData
var stream h264parser.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
}
err = fmt.Errorf("flv: h264 seqhdr invalid")
return
}
self.VideoStreamIdx = len(self.Streams)
self.Streams = append(self.Streams, stream)
@ -227,17 +222,7 @@ 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:
@ -287,19 +272,7 @@ 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,
@ -363,7 +336,7 @@ func NewMuxer(w io.Writer) *Muxer {
return NewMuxerWriteFlusher(bufio.NewWriterSize(w, pio.RecommendBufioSize))
}
var CodecTypes = []av.CodecType{av.H264, av.AAC, av.SPEEX, av.H265}
var CodecTypes = []av.CodecType{av.H264, av.AAC, av.SPEEX}
func (self *Muxer) WriteHeader(streams []av.CodecData) (err error) {
var flags uint8

View File

@ -6,7 +6,7 @@ import (
"strings"
"time"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
type AMF0ParseError struct {

View File

@ -5,8 +5,8 @@ import (
"io"
"time"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/utils/bits/pio"
)
func TsToTime(ts int32) time.Duration {
@ -59,7 +59,6 @@ const (
FRAME_INTER = 2
VIDEO_H264 = 7
VIDEO_H265 = 12
)
type Tag struct {

View File

@ -4,9 +4,9 @@ import (
"errors"
"fmt"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/codec/aacparser"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/codec/aacparser"
"github.com/deepch/vdk/utils/bits/pio"
)
type DecoderConfigDescriptor struct {

View File

@ -4,7 +4,7 @@ import (
"errors"
"fmt"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
type StreamDescriptor struct {

View File

@ -6,7 +6,7 @@ import (
"os"
"strings"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
type Tag uint32

View File

@ -1,6 +1,6 @@
package fmp4io
import "git.r-2.top/kunmeng/vdk/utils/bits/pio"
import "github.com/deepch/vdk/utils/bits/pio"
const AVC1 = Tag(0x61766331)

View File

@ -1,6 +1,6 @@
package fmp4io
import "git.r-2.top/kunmeng/vdk/utils/bits/pio"
import "github.com/deepch/vdk/utils/bits/pio"
const MVEX = Tag(0x6d766578)

View File

@ -1,6 +1,6 @@
package fmp4io
import "git.r-2.top/kunmeng/vdk/utils/bits/pio"
import "github.com/deepch/vdk/utils/bits/pio"
const FTYP = Tag(0x66747970)

View File

@ -3,7 +3,7 @@ package fmp4io
import (
"fmt"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
const MOOF = Tag(0x6d6f6f66)

View File

@ -4,7 +4,7 @@ import (
"math"
"time"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
func GetTime32(b []byte) (t time.Time) {

View File

@ -3,7 +3,7 @@ package fmp4io
import (
"time"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
const MDIA = Tag(0x6d646961)

View File

@ -4,7 +4,7 @@ import (
"fmt"
"time"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
const MOOV = Tag(0x6d6f6f76)

View File

@ -1,8 +1,8 @@
package fmp4io
import (
"git.r-2.top/kunmeng/vdk/format/fmp4/esio"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/format/fmp4/esio"
"github.com/deepch/vdk/utils/bits/pio"
)
const MP4A = Tag(0x6d703461)

View File

@ -1,7 +1,7 @@
package fmp4io
import (
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
const (

View File

@ -3,7 +3,7 @@ package fmp4io
import (
"bytes"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
const DREF = Tag(0x64726566)

View File

@ -3,7 +3,7 @@ package fmp4io
import (
"fmt"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
const STBL = Tag(0x7374626c)

View File

@ -1,6 +1,6 @@
package fmp4io
import "git.r-2.top/kunmeng/vdk/utils/bits/pio"
import "github.com/deepch/vdk/utils/bits/pio"
const SIDX = Tag(0x73696478)

View File

@ -3,7 +3,7 @@ package fragment
import (
"time"
"git.r-2.top/kunmeng/vdk/av"
"github.com/deepch/vdk/av"
)
type Fragment struct {

View File

@ -6,9 +6,9 @@ import (
"sync"
"time"
"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"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/format/fmp4/fmp4io"
"github.com/deepch/vdk/format/fmp4/fragment"
)
var (

View File

@ -1,11 +1,11 @@
package fmp4
import (
"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"
"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"
)
type fragmentWithData struct {

View File

@ -3,12 +3,12 @@ package fmp4
import (
"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/opusparser"
"git.r-2.top/kunmeng/vdk/format/fmp4/esio"
"git.r-2.top/kunmeng/vdk/format/fmp4/fmp4io"
"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"
)
// Track creates a TRAK atom for this stream

View File

@ -3,10 +3,10 @@ package fmp4
import (
"time"
"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"
"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"
)
// TrackFragmenter writes a single audio or video stream as a series of CMAF (fMP4) fragments

View File

@ -1,13 +1,13 @@
package format
import (
"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"
"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"
)
func RegisterAll() {

View File

@ -6,9 +6,9 @@ import (
"io"
"time"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/codec/h264parser"
"git.r-2.top/kunmeng/vdk/format/mkv/mkvio"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/codec/h264parser"
"github.com/deepch/vdk/format/mkv/mkvio"
)
type Demuxer struct {

View File

@ -3,8 +3,8 @@ package mkv
import (
"io"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/av/avutil"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/av/avutil"
)
var CodecTypes = []av.CodecType{av.H264, av.AAC}

View File

@ -3,7 +3,7 @@ package mkv
import (
"time"
"git.r-2.top/kunmeng/vdk/av"
"github.com/deepch/vdk/av"
)
type Stream struct {

View File

@ -6,10 +6,10 @@ import (
"io"
"time"
"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"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/codec/aacparser"
"github.com/deepch/vdk/codec/h264parser"
"github.com/deepch/vdk/format/mp4/mp4io"
)
type Demuxer struct {

View File

@ -3,8 +3,8 @@ package mp4
import (
"io"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/av/avutil"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/av/avutil"
)
var CodecTypes = []av.CodecType{av.H264, av.AAC}

View File

@ -1,10 +1,9 @@
package mp4io
import (
"errors"
"time"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
const MOOF = Tag(0x6d6f6f66)
@ -25,18 +24,17 @@ func (self AVC1Desc) Tag() Tag {
return AVC1
}
// 0x31766568
//0x31766568
const HEV1 = Tag(0x68766331)
func (self HV1Desc) Tag() Tag {
return HEV1
}
// const HVC1 = Tag(0x68766331)
//
// func (self HVC1Desc) Tag() Tag {
// return HVC1
// }
//const HVC1 = Tag(0x68766331)
//func (self HVC1Desc) Tag() Tag {
// return HVC1
//}
const URL = Tag(0x75726c20)
func (self DataReferUrl) Tag() Tag {
@ -306,10 +304,6 @@ 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:
@ -319,10 +313,6 @@ 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)
}
}
@ -611,10 +601,6 @@ 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)
}
}
@ -954,10 +940,6 @@ 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)
}
}
@ -1191,10 +1173,6 @@ 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)
}
}
@ -1277,10 +1255,6 @@ 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)
}
}
@ -1843,10 +1817,6 @@ 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)
}
}
@ -2012,10 +1982,6 @@ 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)
}
}
@ -2325,10 +2291,6 @@ 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)
}
}
@ -2449,10 +2411,6 @@ 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)
}
}
@ -2996,10 +2954,6 @@ 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:
@ -3009,10 +2963,6 @@ 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)
}
}
@ -3177,10 +3127,6 @@ 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)
}
}
@ -3251,10 +3197,6 @@ 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:
@ -3264,10 +3206,6 @@ 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)
}
}

View File

@ -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: `"git.r-2.top/kunmeng/vdk/utils/bits/pio"`}},
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/deepch/vdk/utils/bits/pio"`}},
},
},
&ast.GenDecl{

View File

@ -8,7 +8,7 @@ import (
"strings"
"time"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
type ParseError struct {
@ -387,10 +387,6 @@ 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

View File

@ -3,22 +3,21 @@ 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 {
w io.WriteSeeker
bufw *bufio.Writer
wpos int64
streams []*Stream
NegativeTsMakeZero bool
w io.WriteSeeker
bufw *bufio.Writer
wpos int64
streams []*Stream
}
func NewMuxer(w io.WriteSeeker) *Muxer {
@ -121,7 +120,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.(h265parser.CodecData)
codec := self.CodecData.(h264parser.CodecData)
width, height := codec.Width(), codec.Height()
self.sample.SampleDesc.HV1Desc = &mp4io.HV1Desc{
DataRefIdx: 1,
@ -205,12 +204,8 @@ 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
}
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 {

View File

@ -3,8 +3,8 @@ package mp4
import (
"time"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/format/mp4/mp4io"
)
type Stream struct {

View File

@ -1,6 +1,6 @@
package mp4f
import "git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
import "github.com/deepch/vdk/format/mp4/mp4io"
type FDummy struct {
Data []byte

View File

@ -1,8 +1,8 @@
package mp4fio
import (
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/format/mp4/mp4io"
"github.com/deepch/vdk/utils/bits/pio"
)
func (self MovieFrag) Tag() mp4io.Tag {

View File

@ -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: `"git.r-2.top/kunmeng/vdk/utils/bits/pio"`}},
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/deepch/vdk/utils/bits/pio"`}},
},
},
&ast.GenDecl{

View File

@ -1,8 +1,8 @@
package mp4fio
import (
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/format/mp4/mp4io"
"github.com/deepch/vdk/utils/bits/pio"
)
type ElemStreamDesc struct {

View File

@ -3,18 +3,17 @@ package mp4f
import (
"bufio"
"fmt"
"log"
"os"
"time"
"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"
"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"
)
type Muxer struct {
@ -203,8 +202,7 @@ 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 = "hev1.1.6.L120.90"
self.codecString = fmt.Sprintf("hvc1.%02X%02X%02X", codec.RecordInfo.AVCProfileIndication, codec.RecordInfo.ProfileCompatibility, codec.RecordInfo.AVCLevelIndication)
} else if self.Type() == av.AAC {
codec := self.CodecData.(aacparser.CodecData)
@ -239,15 +237,14 @@ func (self *Muxer) WriteTrailer() (err error) {
return
}
func (element *Muxer) WriteHeader(streams []av.CodecData) error {
func (element *Muxer) WriteHeader(streams []av.CodecData) (err error) {
element.streams = []*Stream{}
for _, stream := range streams {
if err := element.newStream(stream); err != nil {
log.Println("WriteHeader", err)
if err = element.newStream(stream); err != nil {
return
}
}
return nil
return
}
func (element *Muxer) GetInit(streams []av.CodecData) (string, []byte) {
@ -287,9 +284,6 @@ 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)
@ -445,7 +439,7 @@ func (element *Muxer) Finalize() []byte {
}
// PutU32BE func
//PutU32BE func
func PutU32BE(b []byte, v uint32) {
b[0] = byte(v >> 24)
b[1] = byte(v >> 16)

View File

@ -3,10 +3,10 @@ package mp4f
import (
"time"
"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"
"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"
)
type Stream struct {

View File

@ -6,10 +6,10 @@ import (
"io"
"time"
"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"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/codec/aacparser"
"github.com/deepch/vdk/codec/h264parser"
"github.com/deepch/vdk/format/mp4/mp4io"
)
type Demuxer struct {

View File

@ -3,8 +3,8 @@ package mp4
import (
"io"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/av/avutil"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/av/avutil"
)
var CodecTypes = []av.CodecType{av.H264, av.AAC}

View File

@ -1,10 +1,9 @@
package mp4io
import (
"errors"
"time"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
const MOOF = Tag(0x6d6f6f66)
@ -25,18 +24,17 @@ func (self AVC1Desc) Tag() Tag {
return AVC1
}
// 0x31766568
//0x31766568
const HEV1 = Tag(0x68766331)
func (self HV1Desc) Tag() Tag {
return HEV1
}
// const HVC1 = Tag(0x68766331)
//
// func (self HVC1Desc) Tag() Tag {
// return HVC1
// }
//const HVC1 = Tag(0x68766331)
//func (self HVC1Desc) Tag() Tag {
// return HVC1
//}
const URL = Tag(0x75726c20)
func (self DataReferUrl) Tag() Tag {
@ -306,10 +304,6 @@ 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:
@ -319,10 +313,6 @@ 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)
}
}
@ -611,10 +601,6 @@ 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)
}
}
@ -954,10 +940,6 @@ 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)
}
}
@ -1191,10 +1173,6 @@ 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)
}
}
@ -1277,10 +1255,6 @@ 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)
}
}
@ -1843,10 +1817,6 @@ 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)
}
}
@ -2012,10 +1982,6 @@ 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)
}
}
@ -2325,10 +2291,6 @@ 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)
}
}
@ -2449,10 +2411,6 @@ 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)
}
}
@ -2996,10 +2954,6 @@ 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:
@ -3009,10 +2963,6 @@ 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)
}
}
@ -3177,10 +3127,6 @@ 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)
}
}
@ -3251,10 +3197,6 @@ 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:
@ -3264,10 +3206,6 @@ 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)
}
}

View File

@ -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: `"git.r-2.top/kunmeng/vdk/utils/bits/pio"`}},
&ast.ImportSpec{Path: &ast.BasicLit{Kind: token.STRING, Value: `"github.com/deepch/vdk/utils/bits/pio"`}},
},
},
&ast.GenDecl{

View File

@ -8,7 +8,7 @@ import (
"strings"
"time"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
type ParseError struct {
@ -387,12 +387,6 @@ 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

View File

@ -6,19 +6,18 @@ import (
"io"
"time"
"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"
"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 {
w io.WriteSeeker
bufw *bufio.Writer
wpos int64
streams []*Stream
NegativeTsMakeZero bool
w io.WriteSeeker
bufw *bufio.Writer
wpos int64
streams []*Stream
}
func NewMuxer(w io.WriteSeeker) *Muxer {
@ -182,12 +181,8 @@ 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
}
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 {

View File

@ -3,8 +3,8 @@ package mp4
import (
"time"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/format/mp4/mp4io"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/format/mp4/mp4io"
)
type Stream struct {

View File

@ -1,77 +0,0 @@
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()
}

View File

@ -1,383 +1,59 @@
package nvr
import (
"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"
"log"
"os"
"path/filepath"
"strings"
"time"
)
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"
"github.com/deepch/vdk/av"
)
type Muxer struct {
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
serverID, streamName, channelName, streamID, channelID, hostLong, hostShort string
handleFileChange func(bool, string, string, int64, time.Time, time.Time, time.Duration)
name string
patch string
started bool
file *os.File
codec []av.CodecData
buffer []*av.Packet
bufferDur time.Duration
seqDur time.Duration
}
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
//NewMuxer func
func NewMuxer(codec []av.CodecData, name, patch string, seqDur time.Duration) *Muxer {
return &Muxer{
codec: codec,
name: name,
patch: patch,
seqDur: seqDur,
}
m = &Muxer{
mpoint: mpoint,
patch: patch,
h: -1,
gof: &Gof{},
format: format,
limit: limit,
serverID: serverID,
streamName: streamName,
channelName: channelName,
streamID: streamID,
channelID: channelID,
hostLong: hostLong,
hostShort: hostShort,
handleFileChange: c,
}
return
}
func (m *Muxer) WriteHeader(streams []av.CodecData) (err error) {
m.gof.Streams = streams
if m.format == MP4 {
return m.OpenMP4()
}
return
//WritePacket func
func (obj *Muxer) CodecUpdate(val []av.CodecData) {
obj.codec = val
}
func (m *Muxer) WritePacket(pkt av.Packet) (err error) {
if len(m.gof.Streams) == 0 {
return
//WritePacket func
func (obj *Muxer) WritePacket(pkt *av.Packet) (err error) {
if !obj.started && pkt.IsKeyFrame {
obj.started = true
}
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)
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
}
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()
}
//Close func
func (obj *Muxer) Close() {
return
}

View File

@ -1,8 +0,0 @@
package nvr
import "git.r-2.top/kunmeng/vdk/av"
type Stream struct {
codec av.CodecData
idx int
}

View File

@ -4,11 +4,11 @@ import (
"bytes"
"os"
"git.r-2.top/kunmeng/vdk/codec/h265parser"
"github.com/deepch/vdk/codec/h265parser"
"git.r-2.top/kunmeng/vdk/codec/h264parser"
"github.com/deepch/vdk/codec/h264parser"
"git.r-2.top/kunmeng/vdk/av"
"github.com/deepch/vdk/av"
)
var startCode = []byte{0, 0, 0, 1}

View File

@ -14,11 +14,11 @@ import (
"strings"
"time"
"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"
"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"
)
var Debug bool
@ -258,10 +258,7 @@ func (self *Conn) RxBytes() uint64 {
}
func (self *Conn) Close() (err error) {
if self.netconn != nil {
return self.netconn.Close()
}
return
return self.netconn.Close()
}
func (self *Conn) pollCommand() (err error) {
@ -1626,15 +1623,20 @@ func (self *Conn) handshakeServer() (err error) {
clitime := pio.U32BE(C1[0:4])
srvtime := clitime
srvver := uint32(0x0d0e0a0d)
cliver := pio.U32BE(C1[4:8])
var ok bool
var digest []byte
if ok, digest = hsParse1(C1, hsClientPartialKey, hsServerFullKey); ok {
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
}
hsCreate01(S0S1, srvtime, srvver, hsServerPartialKey)
hsCreate2(S2, digest)
} else {
copy(S1, C2)
copy(S2, C1)
copy(S1, C1)
copy(S2, C2)
}
if _, err = self.bufw.Write(S0S1S2); err != nil {

View File

@ -9,6 +9,7 @@ import (
"encoding/hex"
"fmt"
"io"
//"log"
"net"
"net/textproto"
"net/url"
@ -16,13 +17,13 @@ import (
"strings"
"time"
"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"
"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"
)
var ErrCodecDataChange = fmt.Errorf("rtsp: codec data change, please call HandleCodecDataChange()")
@ -40,10 +41,9 @@ const (
)
type Client struct {
DebugRtsp bool
DebugRtp bool
DisableAudio bool
Headers []string
DebugRtsp bool
DebugRtp bool
Headers []string
SkipErrRtpBlock bool
@ -147,12 +147,7 @@ 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 {
@ -700,9 +695,7 @@ func (self *Client) Describe() (streams []sdp.Media, err error) {
self.streams = []*Stream{}
for _, media := range medias {
stream := &Stream{Sdp: media, client: self}
if err = stream.makeCodecData(); err != nil && DebugRtsp {
fmt.Println("rtsp: makeCodecData error", err)
}
stream.makeCodecData()
self.streams = append(self.streams, stream)
streams = append(streams, media)
}
@ -774,7 +767,7 @@ func (self *Stream) timeScale() int {
func (self *Stream) makeCodecData() (err error) {
media := self.Sdp
if (media.PayloadType >= 96 && media.PayloadType <= 127) || media.Type == av.H264 || media.Type == av.AAC {
if media.PayloadType >= 96 && media.PayloadType <= 127 {
switch media.Type {
case av.H264:
for _, nalu := range media.SpropParameterSets {
@ -1077,44 +1070,12 @@ func (self *Stream) handleRtpPacket(packet []byte) (err error) {
err = fmt.Errorf("rtp: packet too short")
return
}
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
}
}
payloadOffset := 12 + int(packet[0]&0xf)*4
if payloadOffset > len(packet) {
err = fmt.Errorf("rtp: packet too short")
return
}
timestamp := binary.BigEndian.Uint32(packet[4:8])
payload := packet[payloadOffset:]
/*
@ -1191,7 +1152,6 @@ 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

View File

@ -8,7 +8,7 @@ import (
"strconv"
"strings"
"git.r-2.top/kunmeng/vdk/av"
"github.com/deepch/vdk/av"
)
type Session struct {
@ -160,9 +160,6 @@ 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)
}

View File

@ -1 +0,0 @@
package rtsp

View File

@ -3,8 +3,8 @@ package rtsp
import (
"time"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/format/rtsp/sdp"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/format/rtsp/sdp"
)
type Stream struct {

View File

@ -12,18 +12,19 @@ import (
"html"
"io"
"log"
"math"
"net"
"net/url"
"strconv"
"strings"
"time"
"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"
"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"
)
const (
@ -37,11 +38,8 @@ const (
)
const (
RTPHeaderSize = 12
RTCPSenderReport = 200
RTCPReceiverReport = 201
RTPHeaderSize = 12
)
const (
DESCRIBE = "DESCRIBE"
OPTIONS = "OPTIONS"
@ -92,10 +90,6 @@ type RTSPClient struct {
FPS int
WaitCodec bool
chTMP int
timestamp int64
sequenceNumber int
end int
offset int
}
type RTSPClientOptions struct {
@ -153,12 +147,9 @@ 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)
@ -247,146 +238,6 @@ 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
@ -697,6 +548,285 @@ 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
@ -807,21 +937,16 @@ func (client *RTSPClient) CodecUpdateVPS(val []byte) {
}
// Println mini logging functions
//Println mini logging functions
func (client *RTSPClient) Println(v ...interface{}) {
if client.options.Debug {
log.Println(v)
}
}
// binSize
//binSize
func binSize(val int) []byte {
buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, uint32(val))
return buf
}
func isRTCPPacket(content []byte) bool {
rtcpPacketType := content[5]
return rtcpPacketType == RTCPSenderReport || rtcpPacketType == RTCPReceiverReport
}

View File

@ -1,290 +0,0 @@
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,
})
}

View File

@ -25,7 +25,6 @@ type ProxyConn struct {
cseq int
session string
protocol int
in int
}
type Proxy struct {
@ -41,6 +40,7 @@ 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,7 +156,6 @@ 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:
@ -166,46 +165,45 @@ 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: " + 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: " + strconv.Itoa(self.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: " + cseq + "\r\nSession: " + self.session + "\r\n\r\n"))
_, 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"))
if err != nil {
return err
}
return nil
}
_, 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"))
_, 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"))
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: " + 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: " + strconv.Itoa(self.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: " + cseq + "\r\n\r\n"))
_, 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"))
if err != nil {
return err
}
self.playing = true
case TEARDOWN:
self.netconn.Close()
return errors.New("exit")
default:
return errors.New("metod not found " + fistStringsSlice[0])
return errors.New("metod not found")
}
return nil

View File

@ -7,7 +7,7 @@ import (
"net/url"
"time"
"git.r-2.top/kunmeng/vdk/av"
"github.com/deepch/vdk/av"
)
const (
@ -30,6 +30,7 @@ const (
LocalCache int = 3
)
//
const (
StreamTypeH264 = 0x1b
StreamTypeH265 = 0x24

View File

@ -6,12 +6,11 @@ import (
"io"
"time"
"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"
"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"
)
type Demuxer struct {
@ -23,8 +22,8 @@ type Demuxer struct {
pmt *tsio.PMT
streams []*Stream
tshdr []byte
AnnexB bool
stage int
stage int
}
func NewDemuxer(r io.Reader) *Demuxer {
@ -119,8 +118,6 @@ 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
@ -190,7 +187,7 @@ func (self *Demuxer) readTSPacket() (err error) {
return
}
func (self *Stream) addPacket(payload []byte, timedelta time.Duration, fixed time.Duration) {
func (self *Stream) addPacket(payload []byte, timedelta time.Duration) {
dts := self.dts
pts := self.pts
@ -202,8 +199,6 @@ func (self *Stream) addPacket(payload []byte, timedelta time.Duration, fixed tim
if self.pt > 0 {
dur = dts + timedelta - self.pt
} else {
dur = fixed
}
self.pt = dts + timedelta
@ -232,16 +227,8 @@ 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
@ -256,7 +243,7 @@ func (self *Stream) payloadEnd() (n int, err error) {
return
}
}
self.addPacket(payload[hdrlen:framelen], delta, time.Duration(samples)*time.Second/time.Duration(config.SampleRate))
self.addPacket(payload[hdrlen:framelen], delta)
n++
delta += time.Duration(samples) * time.Second / time.Duration(config.SampleRate)
payload = payload[framelen:]
@ -265,44 +252,25 @@ 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)
fps := self.fps
if self.fps == 0 {
fps = 25
}
self.addPacket(b, time.Duration(0), (1000*time.Millisecond)/time.Duration(fps))
n++
}
b := make([]byte, 4+len(nalu))
pio.PutU32BE(b[0:4], uint32(len(nalu)))
copy(b[4:], nalu)
self.addPacket(b, time.Duration(0))
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 {
return

View File

@ -3,8 +3,8 @@ package ts
import (
"io"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/av/avutil"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/av/avutil"
)
func Handler(h *avutil.RegisterHandler) {

View File

@ -2,17 +2,16 @@ package ts
import (
"fmt"
"git.r-2.top/kunmeng/vdk/codec/h265parser"
"io"
"time"
"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"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/codec/aacparser"
"github.com/deepch/vdk/codec/h264parser"
"github.com/deepch/vdk/format/ts/tsio"
)
var CodecTypes = []av.CodecType{av.H264, av.H265, av.AAC}
var CodecTypes = []av.CodecType{av.H264, av.AAC}
type Muxer struct {
w io.Writer
@ -68,16 +67,11 @@ func (self *Muxer) newStream(idx int, codec av.CodecData) (err error) {
return
}
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 {
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 {
return
}
streamW.tsw.ContinuityCounter++
}
return
}
@ -85,7 +79,7 @@ func (self *Muxer) writePaddingTSPackets(streamW *Stream) (err error) {
func (self *Muxer) WriteTrailer() (err error) {
if self.PaddingToMakeCounterCont {
for _, stream := range self.streams {
if err = self.writePaddingTSPackets(stream); err != nil {
if err = self.writePaddingTSPackets(stream.tsw); err != nil {
return
}
}
@ -124,11 +118,6 @@ 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,
})
}
}
@ -216,36 +205,6 @@ 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
}

View File

@ -3,8 +3,8 @@ package ts
import (
"time"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/format/ts/tsio"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/format/ts/tsio"
)
type Stream struct {
@ -17,9 +17,9 @@ type Stream struct {
streamId uint8
streamType uint8
tsw *tsio.TSWriter
idx int
fps uint
tsw *tsio.TSWriter
idx int
iskeyframe bool
pts, dts, pt time.Duration
data []byte

View File

@ -5,7 +5,7 @@ import (
"io"
"time"
"git.r-2.top/kunmeng/vdk/utils/bits/pio"
"github.com/deepch/vdk/utils/bits/pio"
)
const (
@ -33,10 +33,8 @@ var ErrParsePMT = fmt.Errorf("invalid PMT")
var ErrParsePAT = fmt.Errorf("invalid PAT")
const (
ElementaryStreamTypeH264 = 0x1B
ElementaryStreamTypeAdtsAAC = 0x0F
ElementaryStreamTypeAlignmentDescriptor = 0x06
ElementaryStreamTypeH265 = 0x24
ElementaryStreamTypeH264 = 0x1B
ElementaryStreamTypeAdtsAAC = 0x0F
)
type PATEntry struct {
@ -517,7 +515,7 @@ func NewTSWriter(pid uint16) *TSWriter {
return w
}
// TSHeader func
//TSHeader func
type TSHeader struct {
PID uint
PCR uint64
@ -529,7 +527,7 @@ type TSHeader struct {
HeaderLength uint
}
// WriteTSHeader func
//WriteTSHeader func
func WriteTSHeader(w io.Writer, element TSHeader, dataLength int) (written int, err error) {
var flags, extFlags uint
@ -689,13 +687,13 @@ func makeRepeatValBytes(val byte, n int) []byte {
return b
}
// WriteRepeatVal func
//WriteRepeatVal func
func WriteRepeatVal(w io.Writer, val byte, n int) (err error) {
_, err = w.Write(makeRepeatValBytes(val, n))
return
}
// WriteUInt64 func
//WriteUInt64 func
func WriteUInt64(w io.Writer, val uint64, n int) (err error) {
var b [8]byte
for i := n - 1; i >= 0; i-- {
@ -708,12 +706,12 @@ func WriteUInt64(w io.Writer, val uint64, n int) (err error) {
return
}
// WriteUInt func
//WriteUInt func
func WriteUInt(w io.Writer, val uint, n int) (err error) {
return WriteUInt64(w, uint64(val), n)
}
// PCRToUInt func
//PCRToUInt func
func PCRToUInt(pcr uint64) uint64 {
base := pcr / 300
ext := pcr % 300

View File

@ -10,8 +10,8 @@ import (
"github.com/pion/webrtc/v2"
"git.r-2.top/kunmeng/vdk/av"
"git.r-2.top/kunmeng/vdk/codec/h264parser"
"github.com/deepch/vdk/av"
"github.com/deepch/vdk/codec/h264parser"
"github.com/pion/webrtc/v2/pkg/media"
)

View File

@ -7,9 +7,9 @@ import (
"log"
"time"
"git.r-2.top/kunmeng/vdk/codec/h264parser"
"github.com/deepch/vdk/codec/h264parser"
"git.r-2.top/kunmeng/vdk/av"
"github.com/deepch/vdk/av"
"github.com/pion/interceptor"
"github.com/pion/webrtc/v3"
"github.com/pion/webrtc/v3/pkg/media"
@ -65,10 +65,6 @@ 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 {
@ -122,22 +118,13 @@ 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: webrtc.MimeTypeH264,
}, "pion-rtsp-video", "pion-video")
MimeType: "video/h264",
}, "pion-rtsp-video", "pion-rtsp-video")
if err != nil {
return "", err
}
if rtpSender, err := peerConnection.AddTrack(track); err != nil {
if _, 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() {
@ -161,17 +148,8 @@ func (element *Muxer) WriteHeader(streams []av.CodecData, sdp64 string) (string,
if err != nil {
return "", err
}
if rtpSender, err := peerConnection.AddTrack(track); err != nil {
if _, 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}
@ -247,7 +225,8 @@ 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 {
} else if naltype == 1 {
err = tmp.track.WriteSample(media.Sample{Data: append([]byte{0, 0, 0, 1}, nalu...), Duration: pkt.Duration})
}
if err != nil {

55
go.mod
View File

@ -1,56 +1,11 @@
module git.r-2.top/kunmeng/vdk
module github.com/deepch/vdk
go 1.18
go 1.15
require (
github.com/gobwas/ws v1.3.1
github.com/google/uuid v1.3.0
github.com/pion/interceptor v0.1.17
github.com/pion/interceptor v0.1.8
github.com/pion/webrtc/v2 v2.2.26
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
github.com/pion/webrtc/v3 v3.1.24
github.com/quadrifoglio/go-mkv v0.0.0-20180620161916-e7a1fc70199c // indirect
)

447
go.sum
View File

@ -1,301 +1,197 @@
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 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
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/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 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk=
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/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 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA=
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.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
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.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/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 h1:3ZvhNyfmxsAqltQrApLPQMhSFNA+aT87RqyCq4OXmf0=
github.com/pion/datachannel v1.4.21/go.mod h1:oiNyP4gHx2DIwRzX/MFyH0Rz/Gz05OgBlayAI2hAWjg=
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/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E=
github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ=
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.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
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/ice v0.7.18 h1:KbAWlzWRUdX9SmehBh3gYpIFsirjhSQsCw6K2MjYMK0=
github.com/pion/ice v0.7.18/go.mod h1:+Bvnm3nYC6Nnp7VV6glUkuOfToB/AtMRZpOU8ihuf4c=
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/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/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.7 h1:P0UB4Sr6xDWEox0kTVxF0LmQihtCbSAdW0H2nEgkA3U=
github.com/pion/mdns v0.0.7/go.mod h1:4iP2UbeFhLI/vWju/bw6ZfwjJzk0z8DNValjGxR/dD8=
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/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.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/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/rtp v1.6.0/go.mod h1:QgfogHsMBVE/RFNno467U/KBqfUywEH+HK+0rtnwsdI=
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/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/sctp v1.7.10/go.mod h1:EhpTUQu1/lcK3xI+eriS6/96fWetHGCvBi9MSsnaBN0=
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/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/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.6 h1:WuDLhtuFUUVpTfus9ILC4HRyHsW6TdugjEX/QY9OiUw=
github.com/pion/sdp/v3 v3.0.6/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw=
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/srtp v1.5.1/go.mod h1:B+QgX5xPeQTNc1CJStJPHzOlHK66ViMDWTT0HZTCkcA=
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/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/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.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/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/turn/v2 v2.0.4/go.mod h1:1812p4DcGVbYVBTiraUmP50XoKye++AMkbfp+N27mog=
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/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/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.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/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/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/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/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/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.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/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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-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/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/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=
@ -305,159 +201,82 @@ 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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
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-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
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/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/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-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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/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/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/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
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=