feat: dynamic buffer time

This commit is contained in:
langhuihui
2024-06-19 17:33:54 +08:00
parent 7547e04a35
commit d39e3c1ed0
20 changed files with 562 additions and 237 deletions

6
api.go
View File

@@ -65,7 +65,7 @@ func (s *Server) api_Stream_AnnexB_(rw http.ResponseWriter, r *http.Request) {
}
rw.Header().Set("Content-Type", "application/octet-stream")
reader := pkg.NewAVRingReader(publisher.VideoTrack.AVTrack)
err = reader.StartRead(publisher.VideoTrack.IDRing.Load())
err = reader.StartRead(publisher.VideoTrack.GetIDR())
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
@@ -81,7 +81,7 @@ func (s *Server) api_Stream_AnnexB_(rw http.ResponseWriter, r *http.Request) {
var annexb pkg.AnnexB
var t pkg.AVTrack
annexb.DecodeConfig(&t, publisher.VideoTrack.ICodecCtx)
err = annexb.DecodeConfig(&t, publisher.VideoTrack.ICodecCtx)
if t.ICodecCtx == nil {
http.Error(rw, "unsupported codec", http.StatusInternalServerError)
return
@@ -91,7 +91,7 @@ func (s *Server) api_Stream_AnnexB_(rw http.ResponseWriter, r *http.Request) {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
frame.(*pkg.AnnexB).WriteTo(rw)
_, err = frame.(*pkg.AnnexB).WriteTo(rw)
}
func (s *Server) getStreamInfo(pub *Publisher) (res *pb.StreamInfoResponse, err error) {

74
go.mod
View File

@@ -10,24 +10,60 @@ require (
github.com/pion/interceptor v0.1.29
github.com/pion/rtcp v1.2.14
github.com/pion/rtp v1.8.6
github.com/polarsignals/frostdb v0.0.0-20240613134636-1d823f7d7299
github.com/q191201771/naza v0.30.48
github.com/quic-go/quic-go v0.43.1
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de
google.golang.org/grpc v1.63.2
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237
google.golang.org/grpc v1.64.0
google.golang.org/protobuf v1.33.0
)
require (
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect
github.com/RoaringBitmap/roaring v1.9.3 // indirect
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/apache/arrow/go/v16 v16.1.0 // indirect
github.com/benbjohnson/immutable v0.4.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.12.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732 // indirect
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/coreos/etcd v3.3.27+incompatible // indirect
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect
github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/efficientgo/core v1.0.0-rc.2 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.3.2 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v24.3.25+incompatible // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hamba/avro/v2 v2.20.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/oklog/ulid/v2 v2.1.0 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/parquet-go/parquet-go v0.22.0 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pion/datachannel v1.5.6 // indirect
github.com/pion/dtls/v2 v2.2.10 // indirect
github.com/pion/ice/v3 v3.0.7 // indirect
@@ -41,15 +77,31 @@ require (
github.com/pion/transport/v2 v2.2.4 // indirect
github.com/pion/transport/v3 v3.0.2 // indirect
github.com/pion/turn/v3 v3.0.3 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/planetscale/vtprotobuf v0.6.0 // indirect
github.com/polarsignals/iceberg-go v0.0.0-20240502213135-2ee70b71e76b // indirect
github.com/polarsignals/wal v0.0.0-20240514152147-1cd4b81c9b88 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/prometheus/client_golang v1.19.1 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/segmentio/encoding v0.3.6 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/thanos-io/objstore v0.0.0-20240512204237-71ef2d0cf7c4 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.opentelemetry.io/otel v1.27.0 // indirect
go.opentelemetry.io/otel/trace v1.27.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
)
require (
@@ -65,11 +117,11 @@ require (
github.com/pion/webrtc/v4 v4.0.0-beta.13
github.com/shirou/gopsutil/v3 v3.24.3
go.uber.org/mock v0.4.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/tools v0.9.1 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/tools v0.21.0 // indirect
gopkg.in/yaml.v3 v3.0.1
)

172
go.sum
View File

@@ -1,8 +1,24 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU=
github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
github.com/RoaringBitmap/roaring v1.9.3 h1:t4EbC5qQwnisr5PrP9nt0IRhRTb9gMUgQF4t4S2OByM=
github.com/RoaringBitmap/roaring v1.9.3/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
github.com/alchemy/rotoslog v0.2.2 h1:yzAOjaQBKgJvAdPi0sF5KSPMq5f2vNJZEnPr73CPDzQ=
github.com/alchemy/rotoslog v0.2.2/go.mod h1:pOHF0DKryPLaQzjcUlidLVRTksvk9yW75YIu1yYiiEQ=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/apache/arrow/go/v16 v16.1.0 h1:dwgfOya6s03CzH9JrjCBx6bkVb4yPD4ma3haj9p7FXI=
github.com/apache/arrow/go/v16 v16.1.0/go.mod h1:9wnc9mn6vEDTRIm4+27pEjQpRKuTvBaessPoEXQzxWA=
github.com/benbjohnson/immutable v0.4.0 h1:CTqXbEerYso8YzVPxmWxh2gnoRQbbB9X1quUC8+vGZA=
github.com/benbjohnson/immutable v0.4.0/go.mod h1:iAr8OjJGLnLmVUr9MZ/rz4PWUy6Ouc2JLYuMArmvAJM=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bits-and-blooms/bitset v1.12.0 h1:U/q1fAF7xXRhFCrhROzIfffYnu+dlS38vCZtmFVPHmA=
github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bluenviron/mediacommon v1.9.2 h1:EHcvoC5YMXRcFE010bTNf07ZiSlB/e/AdZyG7GsEYN0=
github.com/bluenviron/mediacommon v1.9.2/go.mod h1:lt8V+wMyPw8C69HAqDWV5tsAwzN9u2Z+ca8B6C//+n0=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732 h1:XYUCaZrW8ckGWlCRJKCSoh/iFwlpX316a8yY9IFEzv8=
github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
github.com/chromedp/chromedp v0.9.5 h1:viASzruPJOiThk7c5bueOUY91jGLJVximoEMGoH93rg=
@@ -20,14 +36,30 @@ github.com/cnotch/queue v0.0.0-20200326024423-6e88bdbf2ad4/go.mod h1:zOssjAlNusO
github.com/cnotch/queue v0.0.0-20201224060551-4191569ce8f6/go.mod h1:zOssjAlNusOxvtaqT+EMA+Iyi8rrtKr4/XfzN1Fgoeg=
github.com/cnotch/scheduler v0.0.0-20200522024700-1d2da93eefc5/go.mod h1:F4GE3SZkJZ8an1Y0ZCqvSM3jeozNuKzoC67erG1PhIo=
github.com/cnotch/xlog v0.0.0-20201208005456-cfda439cd3a0/go.mod h1:RW9oHsR79ffl3sR3yMGgxYupMn2btzdtJUwoxFPUE5E=
github.com/coreos/etcd v3.3.27+incompatible h1:QIudLb9KeBsE5zyYxd1mjzRSkzLg9Wf9QlRwFgd6oTA=
github.com/coreos/etcd v3.3.27+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf h1:GOPo6vn/vTN+3IwZBvXX0y5doJfSC7My0cdzelyOCsQ=
github.com/coreos/pkg v0.0.0-20220810130054-c7d1c02cb6cf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
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/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0=
github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/efficientgo/core v1.0.0-rc.2 h1:7j62qHLnrZqO3V3UA0AqOGd5d5aXV3AX6m/NZBHp78I=
github.com/efficientgo/core v1.0.0-rc.2/go.mod h1:FfGdkzWarkuzOlY04VY+bGfb1lWrjaL6x/GLcQ4vJps=
github.com/emitter-io/address v1.0.0/go.mod h1:GfZb5+S/o8694B1GMGK2imUYQyn2skszMvGNA5D84Ug=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
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/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
@@ -39,6 +71,8 @@ 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.2 h1:zlnbNHxumkRvfPWgfXu8RBwyNR1x8wh9cf5PTOCqs9Q=
github.com/gobwas/ws v1.3.2/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.2.0/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=
@@ -50,6 +84,10 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
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/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -58,6 +96,9 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
@@ -67,30 +108,59 @@ github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM=
github.com/hamba/avro/v2 v2.20.1 h1:3WByQiVn7wT7d27WQq6pvBRC00FVOrniP6u67FLA/2E=
github.com/hamba/avro/v2 v2.20.1/go.mod h1:xHiKXbISpb3Ovc809XdzWow+XGTn+Oyf/F9aZbTLAig=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kelindar/process v0.0.0-20170730150328-69a29e249ec3/go.mod h1:+lTCLnZFXOkqwD8sLPl6u4erAc0cP8wFegQHfipz7KE=
github.com/kelindar/rate v1.0.0/go.mod h1:AjT4G+hTItNwt30lucEGZIz8y7Uk5zPho6vurIZ+1Es=
github.com/kelindar/tcp v1.0.0/go.mod h1:JB5hj1cshLU60XrLij2BBxW3JQ4hOye8vqbyvuKb52k=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mcuadros/go-defaults v1.2.0 h1:FODb8WSf0uGaY8elWJAkoLL0Ri6AlZ1bFlenk56oZtc=
github.com/mcuadros/go-defaults v1.2.0/go.mod h1:WEZtHEVIGYVDqkKSWBdWKUVdRyKlMfulPaGDWIVeCWY=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
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=
@@ -106,8 +176,13 @@ github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/parquet-go/parquet-go v0.22.0 h1:9G32efs+11L/MDc0Zt05AuvBubRGAp5lRKufv6pB/B8=
github.com/parquet-go/parquet-go v0.22.0/go.mod h1:3VBP+djJCNuV+D5uSUs2pWQufk2yKO+9pwYvXglsB8Y=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
github.com/phsym/console-slog v0.3.1 h1:Fuzcrjr40xTc004S9Kni8XfNsk+qrptQmyR+wZw9/7A=
github.com/phsym/console-slog v0.3.1/go.mod h1:oJskjp/X6e6c0mGpfP8ELkfKUsrkDifYRAqJQgmdDS0=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pion/datachannel v1.5.5/go.mod h1:iMz+lECmfdCMqFRhXhcA/219B0SQlbpoR2V118yimL0=
github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg=
github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4=
@@ -162,14 +237,35 @@ github.com/pion/turn/v3 v3.0.3/go.mod h1:vw0Dz420q7VYAF3J4wJKzReLHIo2LGp4ev8nXQe
github.com/pion/webrtc/v4 v4.0.0-beta.13 h1:nIhz2viUhaFvKlbLDpF/XQqlsS+PhfYTxd8qcAo1pL8=
github.com/pion/webrtc/v4 v4.0.0-beta.13/go.mod h1:ojwmbdrsIkmRXPumQf9OFIkTJVB9AV/Z9ItMpNvsuhM=
github.com/pixelbender/go-sdp v1.1.0/go.mod h1:6IBlz9+BrUHoFTea7gcp4S54khtOhjCW/nVDLhmZBAs=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/planetscale/vtprotobuf v0.6.0 h1:nBeETjudeJ5ZgBHUz1fVHvbqUKnYOXNhsIEabROxmNA=
github.com/planetscale/vtprotobuf v0.6.0/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
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/polarsignals/frostdb v0.0.0-20240613134636-1d823f7d7299 h1:+hojr9kZJjaP2ec/TAhmk2Cm0H/xyBRW4lbFKNT+71g=
github.com/polarsignals/frostdb v0.0.0-20240613134636-1d823f7d7299/go.mod h1:6n9DbDuO0wTtg26S5hoZzrA+pEQRYAB1mpN5Z4U5nqI=
github.com/polarsignals/iceberg-go v0.0.0-20240502213135-2ee70b71e76b h1:Dbm5itapR0uYIMujR8OntWpDJ/nm5OM6JiaKauLcZ4Y=
github.com/polarsignals/iceberg-go v0.0.0-20240502213135-2ee70b71e76b/go.mod h1:5T9ChEZjRNhAGGLwH1cqzDA7wXB84SmU+WkXQr/ZAjo=
github.com/polarsignals/wal v0.0.0-20240514152147-1cd4b81c9b88 h1:FZvQW8MXcNjwLfWDRAatOA83Pof5+iKW7veuInygBXY=
github.com/polarsignals/wal v0.0.0-20240514152147-1cd4b81c9b88/go.mod h1:EVDHAAe+7GQ33A1/x+/gE+sBPN4toQ0XG5RoLD49xr8=
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 v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/q191201771/naza v0.30.48 h1:lbYUaa7A15kJKYwOiU4AbFS1Zo8oQwppl2tLEbJTqnw=
github.com/q191201771/naza v0.30.48/go.mod h1:n+dpJjQSh90PxBwxBNuifOwQttywvSIN5TkWSSYCeBk=
github.com/quic-go/quic-go v0.43.1 h1:fLiMNfQVe9q2JvSsiXo4fXOEguXHGGl9+6gLp4RPeZQ=
github.com/quic-go/quic-go v0.43.1/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
@@ -179,6 +275,9 @@ github.com/samber/slog-formatter v1.0.0/go.mod h1:c7pRfwhCfZQNzJz+XirmTveElxXln7
github.com/samber/slog-multi v1.0.0 h1:snvP/P5GLQ8TQh5WSqdRaxDANW8AAA3egwEoytLsqvc=
github.com/samber/slog-multi v1.0.0/go.mod h1:uLAvHpGqbYgX4FSL0p1ZwoLuveIAJvBECtE07XmYvFo=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg=
github.com/segmentio/encoding v0.3.6 h1:E6lVLyDPseWEulBmCmAKPanDd3jiyGDo5gMcugCRwZQ=
github.com/segmentio/encoding v0.3.6/go.mod h1:n0JeuIqEQrQoPDGsjo8UNd1iA0U8d8+oHAA4E3G3OxM=
github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE=
github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
@@ -190,8 +289,10 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/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=
@@ -199,6 +300,8 @@ github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
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/thanos-io/objstore v0.0.0-20240512204237-71ef2d0cf7c4 h1:7p7g2AVMNRCTHbtmJVjhNKJhRgiI9U3a9FN5ZfgjJMM=
github.com/thanos-io/objstore v0.0.0-20240512204237-71ef2d0cf7c4/go.mod h1:CuSIQu7lCntygNhEGKdLZLaoA8FtpAiC+454oLTXeUY=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
@@ -207,6 +310,20 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
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=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg=
go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ=
go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw=
go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -219,15 +336,15 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg=
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/mod v0.3.0/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.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
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=
@@ -244,13 +361,15 @@ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/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-20201020160332-67f06af15bc9/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/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -261,12 +380,14 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/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-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/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=
@@ -279,8 +400,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
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=
@@ -300,8 +421,9 @@ golang.org/x/text v0.4.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.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -309,20 +431,22 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
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.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0=
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM=
google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.15.0 h1:2lYxjRbTYyxkJxlhC+LvJIx3SsANPdRybu1tGj9/OrQ=
gonum.org/v1/gonum v0.15.0/go.mod h1:xzZVBJBtS+Mz4q0Yl2LJTk+OxOg4jiXZ7qBoM0uISGo=
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4=
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
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=

View File

@@ -3,6 +3,7 @@ package pkg
import (
"context"
"log/slog"
"m7s.live/m7s/v5/pkg/config"
"time"
)
@@ -19,7 +20,6 @@ const (
type AVRingReader struct {
RingReader
mode int
Track *AVTrack
State byte
FirstSeq uint32
@@ -40,22 +40,18 @@ func (r *AVRingReader) DecConfChanged() bool {
func NewAVRingReader(t *AVTrack) *AVRingReader {
t.Debug("create reader")
t.Ready.Await()
t.Info("reader +1", "count", t.ReaderCount.Add(1))
return &AVRingReader{
Track: t,
}
}
func (r *AVRingReader) readFrame() (err error) {
err = r.ReadNext()
if err != nil {
return err
func (r *AVRingReader) readFrame(mode int) (err error) {
if err = r.ReadNext(); err != nil {
return
}
// 超过一半的缓冲区大小说明Reader太慢需要丢帧
if r.mode != SUBMODE_BUFFER && r.State == READSTATE_NORMAL && r.Track.LastValue.Sequence-r.Value.Sequence > uint32(r.Track.Size/2) {
idr := r.Track.IDRing.Load()
if idr != nil && idr.Value.Sequence > r.Value.Sequence {
if mode != SUBMODE_BUFFER && r.State == READSTATE_NORMAL && r.Track.LastValue.Sequence-r.Value.Sequence > uint32(r.Track.Size/2) {
if idr := r.Track.GetIDR(); idr != nil && idr.Value.Sequence > r.Value.Sequence {
r.Warn("reader too slow", "lastSeq", r.Track.LastValue.Sequence, "seq", r.Value.Sequence)
return r.Read(idr)
}
@@ -63,19 +59,18 @@ func (r *AVRingReader) readFrame() (err error) {
return
}
func (r *AVRingReader) ReadFrame(mode int) (err error) {
r.mode = mode
func (r *AVRingReader) ReadFrame(conf *config.Subscribe) (err error) {
switch r.State {
case READSTATE_INIT:
r.Info("start read", "mode", mode)
r.Info("start read", "mode", conf.SubMode)
startRing := r.Track.Ring
idr := r.Track.IDRing.Load()
idr := r.Track.GetIDR()
if idr != nil {
startRing = idr
} else {
r.Warn("no IDRring", "track", r.Track.FourCC().String())
}
switch mode {
switch conf.SubMode {
case SUBMODE_REAL:
if idr != nil {
r.State = READSTATE_FIRST
@@ -85,7 +80,16 @@ func (r *AVRingReader) ReadFrame(mode int) (err error) {
case SUBMODE_NOJUMP:
r.State = READSTATE_NORMAL
case SUBMODE_BUFFER:
if idr := r.Track.HistoryRing.Load(); idr != nil {
for {
currentBft := r.Track.CurrentBufferTime()
if delta := conf.BufferTime - currentBft; delta > 0 {
r.Info("wait buffer", "currentBft", currentBft, "delta", delta)
time.Sleep(delta)
} else {
break
}
}
if idr := r.Track.GetHistoryIDR(conf.BufferTime); idr != nil {
startRing = idr
}
r.State = READSTATE_NORMAL
@@ -101,7 +105,7 @@ func (r *AVRingReader) ReadFrame(mode int) (err error) {
r.FirstSeq = r.Value.Sequence
r.Info("first frame read", "firstTs", r.FirstTs, "firstSeq", r.FirstSeq)
case READSTATE_FIRST:
if idr := r.Track.IDRing.Load(); idr.Value.Sequence != r.FirstSeq {
if idr := r.Track.GetIDR(); idr.Value.Sequence != r.FirstSeq {
if err = r.Read(idr); err != nil {
return
}
@@ -109,7 +113,7 @@ func (r *AVRingReader) ReadFrame(mode int) (err error) {
r.Info("jump", "skipSeq", idr.Value.Sequence-r.FirstSeq, "skipTs", r.SkipTs)
r.State = READSTATE_NORMAL
} else {
if err = r.readFrame(); err != nil {
if err = r.readFrame(conf.SubMode); err != nil {
return
}
r.beforeJump = r.Value.Timestamp - r.FirstTs
@@ -119,7 +123,7 @@ func (r *AVRingReader) ReadFrame(mode int) (err error) {
}
}
case READSTATE_NORMAL:
if err = r.readFrame(); err != nil {
if err = r.readFrame(conf.SubMode); err != nil {
return
}
}

View File

@@ -85,7 +85,7 @@ func (config *Config) Get(key string) (v *Config) {
}
}
func (config Config) Has(key string) (ok bool) {
func (config *Config) Has(key string) (ok bool) {
if config.propsMap == nil {
return false
}
@@ -116,19 +116,26 @@ func (config *Config) Parse(s any, prefix ...string) {
if t.Kind() == reflect.Pointer {
t, v = t.Elem(), v.Elem()
}
config.Ptr = v
config.Default = v.Interface()
if len(prefix) > 0 { // 读取环境变量
envKey := strings.Join(prefix, "_")
if envValue := os.Getenv(envKey); envValue != "" {
envv := config.assign(strings.ToLower(prefix[0]), envValue)
config.Env = envv.Interface()
config.Ptr.Set(envv)
if l := len(prefix); l > 0 { // 读取环境变量
name := strings.ToLower(prefix[l-1])
if tag := config.tag.Get("default"); tag != "" {
v.Set(config.assign(name, tag))
config.Default = v.Interface()
}
if envValue := os.Getenv(strings.Join(prefix, "_")); envValue != "" {
v.Set(config.assign(name, envValue))
config.Env = v.Interface()
}
}
if t.Kind() == reflect.Struct && t != regexpType {
for i, j := 0, t.NumField(); i < j; i++ {
ft, fv := t.Field(i), v.Field(i)
if !ft.IsExported() {
continue
}
@@ -143,8 +150,9 @@ func (config *Config) Parse(s any, prefix ...string) {
name, _, _ = strings.Cut(tag, ",")
}
prop := config.Get(name)
prop.Parse(fv, append(prefix, strings.ToUpper(ft.Name))...)
prop.tag = ft.Tag
prop.Parse(fv, append(prefix, strings.ToUpper(ft.Name))...)
for _, kv := range strings.Split(ft.Tag.Get("enum"), ",") {
kvs := strings.Split(kv, ":")
if len(kvs) != 2 {
@@ -340,8 +348,7 @@ func (config *Config) assign(k string, v any) (target reflect.Value) {
},
})
tmpValue := reflect.New(tmpStruct)
tmpByte, _ := yaml.Marshal(map[string]any{k: v})
yaml.Unmarshal(tmpByte, tmpValue.Interface())
yaml.Unmarshal([]byte(fmt.Sprintf("%s: %v", k, v)), tmpValue.Interface())
target = tmpValue.Elem().Field(0)
}
return

View File

@@ -2,6 +2,7 @@ package config
import (
"fmt"
"m7s.live/m7s/v5/pkg/util"
"regexp"
"strings"
"time"
@@ -31,13 +32,10 @@ type Publish struct {
DelayCloseTimeout time.Duration `desc:"延迟自动关闭(无订阅时)"` // 延迟自动关闭(无订阅时)
IdleTimeout time.Duration `desc:"空闲(无订阅)超时"` // 空闲(无订阅)超时
PauseTimeout time.Duration `default:"30s" desc:"暂停超时时间"` // 暂停超时
BufferTime time.Duration `desc:"缓冲长度(单位:秒)0代表取最近关键帧"` // 缓冲长度(单位:秒)0代表取最近关键帧
BufferTime time.Duration `desc:"缓冲0代表取最近关键帧"` // 缓冲长度(单位:秒)0代表取最近关键帧
Speed float64 `default:"0" desc:"倍速"` // 倍速0 为不限速
Key string `desc:"发布鉴权key"` // 发布鉴权key
SecretArgName string `default:"secret" desc:"发布鉴权参数名"` // 发布鉴权参数名
ExpireArgName string `default:"expire" desc:"发布鉴权失效时间参数名"` // 发布鉴权失效时间参数名
MinRingSize int `default:"100" desc:"最小 RingSize"` // 最小缓冲区大小
MaxRingSize int `default:"1024" desc:"最大 RingSize"` // 最大缓冲区大小
RingSize util.Range[int] `default:"20-1024" desc:"RingSize范围"` // 缓冲区大小范围
}
func (c *Publish) GetPublishConfig() *Publish {
@@ -47,21 +45,13 @@ func (c *Publish) GetPublishConfig() *Publish {
type Subscribe struct {
SubAudio bool `default:"true" desc:"是否订阅音频"`
SubVideo bool `default:"true" desc:"是否订阅视频"`
SubVideoArgName string `default:"vts" desc:"定订阅的视频轨道参数名"` // 指定订阅的视频轨道参数名
SubAudioArgName string `default:"ats" desc:"指定订阅的音频轨道参数名"` // 指定订阅的音频轨道参数名
SubDataArgName string `default:"dts" desc:"指定订阅的数据轨道参数名"` // 指定订阅的数据轨道参数名
SubModeArgName string `desc:"指定订阅的模式参数名"` // 指定订阅的模式参数名
SubAudioTracks []string `desc:"指定订阅的音频轨道"` // 指定订阅的音频轨道
SubVideoTracks []string `desc:"指定订阅的视频轨道"` // 指定订阅的视频轨道
SubDataTracks []string `desc:"指定订阅的数据轨道"` // 指定订阅的数据轨道
SubMode int `desc:"订阅模式" enum:"0:实时模式,1:首屏后不进行追赶,2:从缓冲最大的关键帧开始播放"` // 0实时模式追赶发布者进度在播放首屏后等待发布者的下一个关键帧然后跳到该帧。1、首屏后不进行追赶。2、从缓冲最大的关键帧开始播放也不追赶需要发布者配置缓存长度
BufferTime time.Duration `desc:"缓冲时长submode=2时有效"`
SubMode int `desc:"订阅模式" enum:"0:实时模式,1:首屏后不进行追赶,2:从缓冲时长的关键帧开始播放"` // 0实时模式追赶发布者进度在播放首屏后等待发布者的下一个关键帧然后跳到该帧。1、首屏后不进行追赶。2、从缓冲最大的关键帧开始播放也不追赶需要发布者配置缓存长度
SyncMode int `desc:"同步模式" enum:"0:采用时间戳同步,1:采用写入时间同步"` // 0采用时间戳同步1采用写入时间同步
IFrameOnly bool `desc:"只要关键帧"` // 只要关键帧
WaitTimeout time.Duration `default:"10s" desc:"等待流超时时间"` // 等待流超时
WriteBufferSize int `desc:"写缓冲大小"` // 写缓冲大小
Key string `desc:"订阅鉴权key"` // 订阅鉴权key
SecretArgName string `default:"secret" desc:"订阅鉴权参数名"` // 订阅鉴权参数名
ExpireArgName string `default:"expire" desc:"订阅鉴权失效时间参数名"` // 订阅鉴权失效时间参数名
Internal bool `default:"false" desc:"是否内部订阅"` // 是否内部订阅
}

View File

@@ -1,40 +1,48 @@
package pkg
import (
"sync/atomic"
"fmt"
"log/slog"
"m7s.live/m7s/v5/pkg/util"
"sync"
"time"
)
type RingWriter struct {
*util.Ring[AVFrame]
IDRingList //最近的关键帧位置,首屏渲染
ReaderCount atomic.Int32
sync.RWMutex
IDRingList util.List[*util.Ring[AVFrame]] // 关键帧链表
BufferRange util.Range[time.Duration]
SizeRange util.Range[int]
pool *util.Ring[AVFrame]
poolSize int
Size int
LastValue *AVFrame
SLogger *slog.Logger
}
func NewRingWriter(n int) (rb *RingWriter) {
func NewRingWriter(sizeRange util.Range[int]) (rb *RingWriter) {
rb = &RingWriter{
Size: n,
Ring: util.NewRing[AVFrame](n),
Size: sizeRange[0],
Ring: util.NewRing[AVFrame](sizeRange[0]),
SizeRange: sizeRange,
}
rb.LastValue = &rb.Value
rb.LastValue.StartWrite()
rb.IDRingList.Init()
return
}
func (rb *RingWriter) Resize(size int) {
if size > 0 {
rb.Glow(size)
rb.glow(size)
} else {
rb.Reduce(-size)
rb.reduce(-size)
}
}
func (rb *RingWriter) Glow(size int) (newItem *util.Ring[AVFrame]) {
func (rb *RingWriter) glow(size int) (newItem *util.Ring[AVFrame]) {
before, poolBefore := rb.Size, rb.poolSize
if newCount := size - rb.poolSize; newCount > 0 {
newItem = util.NewRing[AVFrame](newCount).Link(rb.pool)
rb.poolSize = 0
@@ -47,50 +55,117 @@ func (rb *RingWriter) Glow(size int) (newItem *util.Ring[AVFrame]) {
}
rb.Link(newItem)
rb.Size += size
rb.SLogger.Debug("glow", "size", fmt.Sprintf("%d -> %d", before, rb.Size), "pool", fmt.Sprintf("%d -> %d", poolBefore, rb.poolSize))
return
}
func (rb *RingWriter) recycle(r *util.Ring[AVFrame]) {
if rb.pool == nil {
rb.pool = r
} else {
rb.pool.Link(r)
}
}
func (rb *RingWriter) Reduce(size int) (r *util.Ring[AVFrame]) {
r = rb.Unlink(size)
func (rb *RingWriter) reduce(size int) {
before, poolBefore := rb.Size, rb.poolSize
r := rb.Unlink(size)
rb.Size -= size
for range size {
if r.Value.TryLock() {
rb.poolSize++
r.Value.Reset()
r.Value.Unlock()
} else {
rb.SLogger.Debug("discard", "seq", r.Value.Sequence)
r.Value.Discard()
r = r.Prev()
r.Unlink(1)
}
r = r.Next()
}
rb.recycle(r)
rb.Size -= size
return
if poolBefore != rb.poolSize {
if rb.pool == nil {
rb.pool = r
} else {
rb.pool.Link(r)
}
}
rb.SLogger.Debug("reduce", "size", fmt.Sprintf("%d -> %d", before, rb.Size), "pool", fmt.Sprintf("%d -> %d", poolBefore, rb.poolSize))
}
func (rb *RingWriter) Dispose() {
rb.SLogger.Debug("dispose")
rb.Value.Ready()
}
func (rb *RingWriter) GetIDR() *util.Ring[AVFrame] {
rb.RLock()
defer rb.RUnlock()
return rb.IDRingList.Back().Value
}
func (rb *RingWriter) GetHistoryIDR(bufTime time.Duration) *util.Ring[AVFrame] {
rb.RLock()
defer rb.RUnlock()
for item := rb.IDRingList.Back(); item != nil; item = item.Prev() {
if item.Value.Value.Timestamp-rb.LastValue.Timestamp > bufTime {
return item.Value
}
}
return nil
}
func (rb *RingWriter) durationFrom(from *util.Ring[AVFrame]) time.Duration {
return rb.Value.Timestamp - from.Value.Timestamp
}
func (rb *RingWriter) CurrentBufferTime() time.Duration {
return rb.BufferRange[1]
}
func (rb *RingWriter) Step() (normal bool) {
isIDR := rb.Value.IDR
next := rb.Next()
if isIDR {
rb.SLogger.Debug("add idr")
rb.Lock()
rb.IDRingList.PushBack(rb.Ring)
rb.Unlock()
}
if rb.IDRingList.Len() > 0 {
oldIDR := rb.IDRingList.Front()
rb.BufferRange[1] = rb.durationFrom(oldIDR.Value)
// do not remove only idr
if next == rb.IDRingList.Back().Value {
if rb.Size < rb.SizeRange[1] {
rb.glow(5)
next = rb.Next()
}
} else if next == oldIDR.Value {
if nextOld := oldIDR.Next(); nextOld != nil && rb.durationFrom(nextOld.Value) > rb.BufferRange[0] {
rb.SLogger.Debug("remove old idr")
rb.Lock()
rb.IDRingList.Remove(oldIDR)
rb.Unlock()
} else {
rb.SLogger.Debug("not enough buffer")
rb.glow(5)
next = rb.Next()
}
} else if rb.BufferRange[1] > rb.BufferRange[0] {
for tmpP, reduceCount := rb.Next(), 0; reduceCount < 5; reduceCount++ {
if tmpP == oldIDR.Value {
break
}
if tmpP = tmpP.Next(); reduceCount == 4 && rb.Size > rb.SizeRange[0] {
rb.reduce(5)
next = rb.Next()
}
}
}
}
rb.LastValue = &rb.Value
nextSeq := rb.LastValue.Sequence + 1
next := rb.Next()
if normal = next.Value.StartWrite(); normal {
next.Value.Reset()
rb.Ring = next
} else {
rb.Reduce(1) //抛弃还有订阅者的节点
rb.Ring = rb.Glow(1) //补充一个新节点
rb.reduce(1) //抛弃还有订阅者的节点
rb.Ring = rb.glow(1) //补充一个新节点
normal = rb.Value.StartWrite()
if !normal {
panic("RingWriter.Step")

View File

@@ -3,9 +3,8 @@ package pkg
import (
"context"
"log/slog"
"m7s.live/m7s/v5/pkg/config"
"reflect"
"slices"
"sync/atomic"
"time"
"m7s.live/m7s/v5/pkg/util"
@@ -27,12 +26,6 @@ type (
Track
}
IDRingList struct {
IDRList []*AVRing
IDRing atomic.Pointer[AVRing]
HistoryRing atomic.Pointer[AVRing]
}
AVTrack struct {
Track
*RingWriter
@@ -57,8 +50,10 @@ func NewAVTrack(args ...any) (t *AVTrack) {
case *AVTrack:
t.Logger = v.Logger.With("subtrack", t.FrameType.String())
t.RingWriter = v.RingWriter
case int:
t.RingWriter = NewRingWriter(v)
case *config.Publish:
t.RingWriter = NewRingWriter(v.RingSize)
t.BufferRange[0] = v.BufferTime
t.RingWriter.SLogger = t.Logger
}
}
t.Ready = util.NewPromise(struct{}{})
@@ -85,13 +80,3 @@ func (t *Track) AddBytesIn(n int) {
func (t *Track) Trace(msg string, fields ...any) {
t.Log(context.TODO(), TraceLevel, msg, fields...)
}
func (p *IDRingList) AddIDR(IDRing *AVRing) {
p.IDRList = append(p.IDRList, IDRing)
p.IDRing.Store(IDRing)
}
func (p *IDRingList) ShiftIDR() {
p.IDRList = slices.Delete(p.IDRList, 0, 1)
p.HistoryRing.Store(p.IDRList[0])
}

View File

@@ -94,14 +94,7 @@ func (r *BufReader) ReadBE32(n int) (num uint32, err error) {
}
func (r *BufReader) Skip(n int) (err error) {
r.recycleFront()
for r.buf.Length < n {
if err = r.eat(); err != nil {
return err
}
}
r.buf.RangeN(n, nil)
return
return r.ReadRange(n, nil)
}
func (r *BufReader) ReadRange(n int, yield func([]byte)) (err error) {
@@ -112,13 +105,24 @@ func (r *BufReader) ReadRange(n int, yield func([]byte)) (err error) {
return
}
n -= r.buf.Length
if yield != nil {
r.buf.Range(yield)
}
r.buf.MoveToEnd()
}
}
return
}
func (r *BufReader) ReadNto(n int, to []byte) (err error) {
l := 0
return r.ReadRange(n, func(buf []byte) {
ll := len(buf)
copy(to[l:l+ll], buf)
l += ll
})
}
func (r *BufReader) ReadBytes(n int) (mem Memory, err error) {
err = r.ReadRange(n, func(buf []byte) {
mem.Buffers = append(mem.Buffers, buf)

View File

@@ -140,8 +140,8 @@ func (sma *ScalableMemoryAllocator) Recycle() {
}
func (sma *ScalableMemoryAllocator) Malloc(size int) (memory []byte) {
if sma == nil {
return make([]byte, size)
if sma == nil || size > MaxBlockSize {
return
}
if EnableCheckSize {
defer sma.checkSize()
@@ -162,9 +162,6 @@ func (sma *ScalableMemoryAllocator) Malloc(size int) (memory []byte) {
child = GetMemoryAllocator(sma.childSize)
sma.size += child.Size
memory = child.Malloc(size)
if memory == nil {
panic(fmt.Errorf("malloc faild %d", size))
}
sma.children = append(sma.children, child)
return
}
@@ -204,7 +201,9 @@ type RecyclableMemory struct {
func (r *RecyclableMemory) NextN(size int) (memory []byte) {
memory = r.ScalableMemoryAllocator.Malloc(size)
if r.RecycleIndexes != nil {
if memory == nil {
memory = make([]byte, size)
} else if r.RecycleIndexes != nil {
r.RecycleIndexes = append(r.RecycleIndexes, r.Count())
}
r.Append(memory)

37
pkg/util/range.go Normal file
View File

@@ -0,0 +1,37 @@
package util
import (
"gopkg.in/yaml.v3"
"strconv"
"strings"
)
type Range[T ~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr] [2]T
func (r *Range[T]) Size() T {
return r[1] - r[0]
}
func (r *Range[T]) Within(x T) bool {
return x >= r[0] && x <= r[1]
}
func (r *Range[T]) Valid() bool {
return r.Size() >= 0
}
func (r *Range[T]) UnmarshalYAML(value *yaml.Node) error {
ss := strings.Split(value.Value, "-")
i64, err := strconv.ParseInt(ss[0], 10, 0)
if err != nil {
return err
}
r[0] = T(i64)
i64, err = strconv.ParseInt(ss[1], 10, 0)
if err != nil {
return err
}
r[1] = T(i64)
return nil
}

View File

@@ -11,7 +11,6 @@ import (
"strings"
gatewayRuntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/mcuadros/go-defaults"
"google.golang.org/grpc"
"gopkg.in/yaml.v3"
. "m7s.live/m7s/v5/pkg"
@@ -35,7 +34,6 @@ func (plugin *PluginMeta) Init(s *Server, userConfig map[string]any) {
if !ok {
panic("plugin must implement IPlugin")
}
defaults.SetDefaults(instance)
p := reflect.ValueOf(instance).Elem().FieldByName("Plugin").Addr().Interface().(*Plugin)
p.handler = instance
p.Meta = plugin
@@ -49,6 +47,7 @@ func (plugin *PluginMeta) Init(s *Server, userConfig map[string]any) {
}
p.Config.Parse(p.GetCommonConf())
p.Config.Parse(instance, strings.ToUpper(plugin.Name))
for _, fname := range MergeConfigs {
if name := strings.ToLower(fname); p.Config.Has(name) {
p.Config.Get(name).ParseGlobal(s.Config.Get(name))
@@ -62,8 +61,9 @@ func (plugin *PluginMeta) Init(s *Server, userConfig map[string]any) {
p.Config.ParseDefaultYaml(defaultConf)
}
}
p.Config.ParseUserFile(userConfig)
finalConfig, _ := yaml.Marshal(p.Config.GetMap())
p.Debug("config", "detail", string(finalConfig))
if s.DisableAll {
p.Disabled = true
}
@@ -274,8 +274,7 @@ func (p *Plugin) Publish(streamPath string, options ...any) (publisher *Publishe
if onAuthPub, ok := p.server.OnAuthPubs[p.Meta.Name]; ok {
authPromise := util.NewPromise(publisher)
onAuthPub(authPromise)
<-authPromise.Done()
if err = context.Cause(authPromise.Context); err != util.ErrResolve {
if _, err = authPromise.Await(); err != nil {
p.Warn("auth failed", "error", err)
return
}
@@ -287,7 +286,7 @@ func (p *Plugin) Publish(streamPath string, options ...any) (publisher *Publishe
v(&publisher.Publish)
}
}
publisher.Init(p, streamPath, options...)
publisher.Init(p, streamPath, &publisher.Publish, options...)
_, err = p.server.Call(publisher)
return
}
@@ -310,7 +309,7 @@ func (p *Plugin) Pull(streamPath string, url string, options ...any) (puller *Pu
}()
}
}
puller.Init(p, streamPath, options...)
puller.Init(p, streamPath, &puller.Publish, options...)
_, err = p.server.Call(puller)
return
}
@@ -321,8 +320,7 @@ func (p *Plugin) Subscribe(streamPath string, options ...any) (subscriber *Subsc
if onAuthSub, ok := p.server.OnAuthSubs[p.Meta.Name]; ok {
authPromise := util.NewPromise(subscriber)
onAuthSub(authPromise)
<-authPromise.Done()
if err = context.Cause(authPromise.Context); err != util.ErrResolve {
if _, err = authPromise.Await(); err != nil {
p.Warn("auth failed", "error", err)
return
}
@@ -334,7 +332,7 @@ func (p *Plugin) Subscribe(streamPath string, options ...any) (subscriber *Subsc
v(&subscriber.Subscribe)
}
}
subscriber.Init(p, streamPath, options...)
subscriber.Init(p, streamPath, &subscriber.Subscribe, options...)
_, err = p.server.Call(subscriber)
return
}
@@ -379,7 +377,7 @@ func (p *Plugin) Push(streamPath string, url string, options ...any) (pusher *Pu
}()
}
}
pusher.Init(p, streamPath, options...)
pusher.Init(p, streamPath, &pusher.Subscribe, options...)
_, err = p.server.Call(pusher)
return
}

View File

@@ -6,14 +6,13 @@ import (
"crypto/tls"
"encoding/json"
"fmt"
"github.com/quic-go/quic-go"
"io"
"m7s.live/m7s/v5"
"net"
"net/http"
"strings"
"time"
"github.com/quic-go/quic-go"
"m7s.live/m7s/v5"
)
type myResponseWriter struct {
@@ -59,12 +58,12 @@ type ConsolePlugin struct {
var _ = m7s.InstallPlugin[ConsolePlugin]()
func (cfg *ConsolePlugin) OnInit() error {
func (cfg *ConsolePlugin) connect() (conn quic.Connection, err error) {
tlsConf := &tls.Config{
InsecureSkipVerify: true,
NextProtos: []string{"monibuca"},
}
conn, err := quic.DialAddr(cfg.Context, cfg.Server, tlsConf, &quic.Config{
conn, err = quic.DialAddr(cfg.Context, cfg.Server, tlsConf, &quic.Config{
KeepAlivePeriod: time.Second * 10,
EnableDatagrams: true,
})
@@ -77,7 +76,7 @@ func (cfg *ConsolePlugin) OnInit() error {
if err = json.Unmarshal(msg[:len(msg)-1], &rMessage); err == nil {
if rMessage["code"].(float64) != 0 {
// cfg.Error("response from console server ", cfg.Server, rMessage["msg"])
return fmt.Errorf("response from console server %s %s", cfg.Server, rMessage["msg"])
return nil, fmt.Errorf("response from console server %s %s", cfg.Server, rMessage["msg"])
} else {
// cfg.reportStream = stream
cfg.Info("response from console server ", cfg.Server, rMessage)
@@ -93,16 +92,27 @@ func (cfg *ConsolePlugin) OnInit() error {
}
}
}
return
}
func (cfg *ConsolePlugin) OnInit() error {
conn, err := cfg.connect()
if err != nil {
return err
}
go func() {
for !cfg.IsStopped() {
for err == nil {
var s quic.Stream
if s, err = conn.AcceptStream(cfg.Context); err == nil {
go cfg.ReceiveRequest(s, conn)
}
}
if !cfg.IsStopped() {
<-time.After(time.Second)
cfg.OnInit()
time.Sleep(time.Second)
conn, err = cfg.connect()
if err != nil {
break
}
}
}()
return err

View File

@@ -60,7 +60,7 @@ func (puller *HDLPuller) Connect(p *m7s.Client) (err error) {
var flvHead [3]byte
var version, flag byte
var reader = head.NewReader()
reader.ReadByteTo(&flvHead[0], &flvHead[1], &flvHead[2], &version, &flag)
err = reader.ReadByteTo(&flvHead[0], &flvHead[1], &flvHead[2], &version, &flag)
if flvHead != [...]byte{'F', 'L', 'V'} {
err = errors.New("not flv file")
} else {
@@ -102,16 +102,19 @@ func (puller *HDLPuller) Pull(p *m7s.Puller) (err error) {
if startTs == 0 {
startTs = timestamp
}
puller.ReadBE(3) // stream id always 0
var frame rtmp.RTMPData
frame.ScalableMemoryAllocator = puller.ScalableMemoryAllocator
mem, err := puller.ReadBytes(int(dataSize))
if err != nil {
if _, err = puller.ReadBE(3); err != nil { // stream id always 0
return err
}
switch t {
var frame rtmp.RTMPData
switch ds := int(dataSize); t {
case FLV_TAG_TYPE_AUDIO, FLV_TAG_TYPE_VIDEO:
mem.CopyTo(frame.NextN(mem.Size))
frame.ScalableMemoryAllocator = puller.ScalableMemoryAllocator
err = puller.ReadNto(ds, frame.NextN(ds))
default:
err = puller.Skip(ds)
}
if err != nil {
return err
}
puller.absTS = offsetTs + (timestamp - startTs)
frame.Timestamp = puller.absTS

22
plugin/monitor/index.go Normal file
View File

@@ -0,0 +1,22 @@
package plugin_monitor
import (
"github.com/polarsignals/frostdb"
"m7s.live/m7s/v5"
)
var _ = m7s.InstallPlugin[MonitorPlugin]()
type MonitorPlugin struct {
m7s.Plugin
columnstore *frostdb.ColumnStore
}
func (cfg *MonitorPlugin) OnInit() (err error) {
cfg.columnstore, err = frostdb.New()
//database, _ := cfg.columnstore.DB(cfg, "monitor")
if err != nil {
return err
}
return
}

View File

@@ -4,6 +4,7 @@ import (
"errors"
"io"
"net"
"runtime/debug"
"m7s.live/m7s/v5"
"m7s.live/m7s/v5/plugin/rtmp/pb"
@@ -47,6 +48,7 @@ func (p *RTMPPlugin) OnTCPConnect(conn *net.TCPConn) {
nc.Destroy()
if p := recover(); p != nil {
err = p.(error)
logger.Error(err.Error(), "stack", string(debug.Stack()))
}
if len(receivers) > 0 {
for _, receiver := range receivers {

View File

@@ -115,13 +115,12 @@ func (nc *NetConnection) simple_handshake(C1 []byte, checkC2 bool) error {
copy(S0S1[5:], "Monibuca")
nc.Write(S0S1)
nc.Write(C1) // S2
C2, err := nc.ReadBytes(C1S1_SIZE)
buf := nc.mediaDataPool.NextN(C1S1_SIZE)
err := nc.ReadNto(C1S1_SIZE, buf)
if err != nil {
return err
}
if checkC2 {
buf := nc.mediaDataPool.NextN(C2.Size)
C2.CopyTo(buf)
if !bytes.Equal(buf[8:], S0S1[9:]) {
return errors.New("C2 Error")
}

View File

@@ -2,6 +2,7 @@ package m7s
import (
"reflect"
"slices"
"sync"
"time"
@@ -128,6 +129,19 @@ func (p *Publisher) RemoveSubscriber(subscriber *Subscriber) {
defer p.Unlock()
p.Subscribers.Remove(subscriber)
p.Info("subscriber -1", "count", p.Subscribers.Length)
if subscriber.BufferTime == p.BufferTime && p.Subscribers.Length > 0 {
p.BufferTime = slices.MaxFunc(p.Subscribers.Items, func(a, b *Subscriber) int {
return int(a.BufferTime - b.BufferTime)
}).BufferTime
} else {
p.BufferTime = p.Plugin.GetCommonConf().Publish.BufferTime
}
if !p.AudioTrack.IsEmpty() {
p.AudioTrack.AVTrack.BufferRange[0] = p.BufferTime
}
if !p.VideoTrack.IsEmpty() {
p.VideoTrack.AVTrack.BufferRange[0] = p.BufferTime
}
if p.State == PublisherStateSubscribed && p.Subscribers.Length == 0 {
p.State = PublisherStateWaitSubscriber
if p.DelayCloseTimeout > 0 {
@@ -142,6 +156,15 @@ func (p *Publisher) AddSubscriber(subscriber *Subscriber) {
subscriber.Publisher = p
if p.Subscribers.AddUnique(subscriber) {
p.Info("subscriber +1", "count", p.Subscribers.Length)
if subscriber.BufferTime > p.BufferTime {
p.BufferTime = subscriber.BufferTime
if !p.AudioTrack.IsEmpty() {
p.AudioTrack.AVTrack.BufferRange[0] = p.BufferTime
}
if !p.VideoTrack.IsEmpty() {
p.VideoTrack.AVTrack.BufferRange[0] = p.BufferTime
}
}
switch p.State {
case PublisherStateTrackAdded, PublisherStateWaitSubscriber:
p.State = PublisherStateSubscribed
@@ -181,7 +204,7 @@ func (p *Publisher) WriteVideo(data IAVFrame) (err error) {
}
t := p.VideoTrack.AVTrack
if t == nil {
t = NewAVTrack(data, p.Logger.With("track", "video"), 20)
t = NewAVTrack(data, p.Logger.With("track", "video"), &p.Publish)
p.Lock()
p.VideoTrack.AVTrack = t
p.VideoTrack.Add(t)
@@ -202,41 +225,18 @@ func (p *Publisher) WriteVideo(data IAVFrame) (err error) {
if t.ICodecCtx == nil {
return ErrUnsupportCodec
}
idr, hidr := t.IDRing.Load(), t.HistoryRing.Load()
var idr *util.Ring[AVFrame]
if t.IDRingList.Len() > 0 {
idr = t.IDRingList.Back().Value
}
if t.Value.IDR {
if t.Ring == idr {
panic("idr ring is full")
}
if idr != nil {
p.GOP = int(t.Value.Sequence - idr.Value.Sequence)
if hidr == nil && p.GOP > 0 {
if l := t.Size - p.GOP; l > p.GetPublishConfig().MinRingSize {
t.Debug("reduce", "gop", p.GOP, "before", t.Size, "after", t.Size-5)
t.Reduce(5) //缩小缓冲环节省内存
t.Debug("check", "real", t.Len())
}
}
}
if p.BufferTime > 0 {
t.IDRingList.AddIDR(t.Ring)
if hidr == nil {
t.HistoryRing.Store(t.Ring)
}
} else {
t.IDRing.Store(t.Ring)
}
if idr == nil {
if t.Ready.IsPending() {
p.Info("ready")
t.Ready.Fulfill(nil)
}
if !p.AudioTrack.IsEmpty() {
p.AudioTrack.IDRing.Store(p.AudioTrack.Ring)
}
} else if nextValue := t.Next(); nextValue == idr || nextValue == hidr {
if t.Size < p.Plugin.GetCommonConf().MaxRingSize {
t.Debug("glow", "gop", p.GOP, "before", t.Size, "after", t.Size+5)
t.Glow(5)
t.Debug("check", "real", t.Len())
} else if idr != nil {
p.GOP = int(t.Value.Sequence - idr.Value.Sequence)
} else {
p.GOP = 0
}
}
p.writeAV(t, data)
@@ -298,7 +298,7 @@ func (p *Publisher) WriteAudio(data IAVFrame) (err error) {
}
t := p.AudioTrack.AVTrack
if t == nil {
t = NewAVTrack(data, p.Logger.With("track", "audio"), 20)
t = NewAVTrack(data, p.Logger.With("track", "audio"), &p.Publish)
p.Lock()
p.AudioTrack.AVTrack = t
p.AudioTrack.Add(t)

View File

@@ -15,7 +15,6 @@ import (
"time"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/mcuadros/go-defaults"
"github.com/phsym/console-slog"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
@@ -146,8 +145,6 @@ func (s *Server) run(ctx context.Context, conf any) (err error) {
s.Error("parsing yml error:", err)
}
}
defaults.SetDefaults(&s.Engine)
defaults.SetDefaults(&s.config)
s.Config.Parse(&s.config)
s.Config.Parse(&s.Engine, "GLOBAL")
if cg != nil {

View File

@@ -9,7 +9,7 @@ import (
"os"
"reflect"
"runtime"
"strconv"
"strings"
"time"
. "m7s.live/m7s/v5/pkg"
@@ -38,7 +38,7 @@ func (p *PubSubBase) GetKey() int {
return p.ID
}
func (ps *PubSubBase) Init(p *Plugin, streamPath string, options ...any) {
func (ps *PubSubBase) Init(p *Plugin, streamPath string, conf any, options ...any) {
ps.Plugin = p
ctx := p.Context
for _, option := range options {
@@ -61,6 +61,23 @@ func (ps *PubSubBase) Init(p *Plugin, streamPath string, options ...any) {
if u, err := url.Parse(streamPath); err == nil {
ps.StreamPath, ps.Args = u.Path, u.Query()
}
// args to config
if len(ps.Args) != 0 {
var c config.Config
c.Parse(conf)
ignores, cc := make(map[string]struct{}), make(map[string]any)
for key, value := range ps.Args {
if strings.HasSuffix(key, "ArgName") {
targetArgName := strings.TrimSuffix(key, "ArgName")
cc[targetArgName] = ps.Args.Get(value[0])[0]
ignores[value[0]] = struct{}{}
delete(cc, value[0])
} else if _, ok := ignores[key]; !ok {
cc[key] = value[0]
}
}
c.ParseModifyFile(cc)
}
ps.StartTime = time.Now()
}
@@ -79,11 +96,7 @@ func PlayBlock[A any, V any](s *Subscriber, onAudio func(A) error, onVideo func(
var awi, vwi int
var startAudioTs, startVideoTs time.Duration
var initState = 0
var prePublisher *Publisher
var subMode = s.SubMode //订阅模式
if s.Args.Has(s.SubModeArgName) {
subMode, _ = strconv.Atoi(s.Args.Get(s.SubModeArgName))
}
prePublisher := s.Publisher
var audioFrame, videoFrame *AVFrame
if s.SubAudio {
a1 = reflect.TypeOf(onAudio).In(0)
@@ -105,6 +118,9 @@ func PlayBlock[A any, V any](s *Subscriber, onAudio func(A) error, onVideo func(
}
}
if at != nil {
if _, err := at.Ready.Await(); err != nil {
return
}
ar = NewAVRingReader(at)
s.AudioReader = ar
ar.StartTs = startAudioTs
@@ -126,6 +142,9 @@ func PlayBlock[A any, V any](s *Subscriber, onAudio func(A) error, onVideo func(
}
}
if vt != nil {
if _, err := vt.Ready.Await(); err != nil {
return
}
vr = NewAVRingReader(vt)
vr.StartTs = startVideoTs
s.VideoReader = vr
@@ -135,7 +154,6 @@ func PlayBlock[A any, V any](s *Subscriber, onAudio func(A) error, onVideo func(
}
createAudioReader()
createVideoReader()
prePublisher = s.Publisher
defer func() {
if ar != nil {
ar.StopRead()
@@ -205,7 +223,7 @@ func PlayBlock[A any, V any](s *Subscriber, onAudio func(A) error, onVideo func(
err = s.Err()
if vr != nil {
for err == nil {
err = vr.ReadFrame(subMode)
err = vr.ReadFrame(&s.Subscribe)
if err == nil {
videoFrame = &vr.Value
err = s.Err()
@@ -259,8 +277,7 @@ func PlayBlock[A any, V any](s *Subscriber, onAudio func(A) error, onVideo func(
ar.SkipTs = vr.SkipTs
}
}
err = ar.ReadFrame(subMode)
if err == nil {
if err = ar.ReadFrame(&s.Subscribe); err == nil {
audioFrame = &ar.Value
err = s.Err()
} else {