v0.1 Writer creates from rtsp flow two files: video in format h264 and audio in format pcm
This commit is contained in:
parent
cd759056e9
commit
992f9d8138
237
writer/cmd/main.go
Normal file
237
writer/cmd/main.go
Normal file
@ -0,0 +1,237 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/bluenviron/gortsplib/v4"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/base"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/description"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/format"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/format/rtph264"
|
||||
"github.com/pion/rtp"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
currentVideoFile *os.File
|
||||
currentAudioFile *os.File
|
||||
fileMu sync.Mutex
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Парсинг URL RTSP
|
||||
u, err := base.ParseURL("rtsp://intercom-video-2.insit.ru/dp-ohusuxzcvzsnpzzvkpyhddnwxuyeyc")
|
||||
if err != nil {
|
||||
log.Fatalln("Ошибка парсинга URL:", err)
|
||||
}
|
||||
|
||||
// Инициализация клиента и подключение к серверу
|
||||
client := gortsplib.Client{}
|
||||
err = client.Start(u.Scheme, u.Host)
|
||||
if err != nil {
|
||||
log.Fatalln("Ошибка соединения:", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// Получение описания
|
||||
desc, _, err := client.Describe(u)
|
||||
if err != nil {
|
||||
log.Fatalln("Ошибка получения описания:", err)
|
||||
}
|
||||
|
||||
// Установка настроек
|
||||
err = client.SetupAll(desc.BaseURL, desc.Medias)
|
||||
if err != nil {
|
||||
log.Fatalln("Ошибка настройки:", err)
|
||||
}
|
||||
|
||||
// Определение формата видео- и аудио-потоков
|
||||
var h264Format *format.H264
|
||||
var g711Format *format.G711
|
||||
for _, media := range desc.Medias {
|
||||
switch media.Formats[0].(type) {
|
||||
case *format.H264:
|
||||
h264Format = media.Formats[0].(*format.H264)
|
||||
case *format.G711:
|
||||
g711Format = media.Formats[0].(*format.G711)
|
||||
}
|
||||
}
|
||||
if h264Format == nil || g711Format == nil {
|
||||
log.Fatalln("Форматы не найдены")
|
||||
}
|
||||
|
||||
// Создание декодеров для видео- и аудио-потоков
|
||||
decoderH264, err := h264Format.CreateDecoder()
|
||||
if err != nil {
|
||||
log.Fatalln("Ошибка создания декодера H264:", err)
|
||||
}
|
||||
decoderG711, err := g711Format.CreateDecoder()
|
||||
if err != nil {
|
||||
log.Fatalln("Ошибка создания декодера G711:", err)
|
||||
}
|
||||
|
||||
// Обработка RTP-пакетов: для видео – запись NAL-ов с префиксом, для аудио – запись PCM-данных.
|
||||
client.OnPacketRTPAny(func(medi *description.Media, forma format.Format, pkt *rtp.Packet) {
|
||||
switch forma.(type) {
|
||||
case *format.H264:
|
||||
nalus, err := decoderH264.Decode(pkt)
|
||||
if err != nil && !errors.Is(err, rtph264.ErrMorePacketsNeeded) {
|
||||
log.Printf("Ошибка декодирования H264: %v", err)
|
||||
return
|
||||
}
|
||||
fileMu.Lock()
|
||||
defer fileMu.Unlock()
|
||||
if currentVideoFile != nil {
|
||||
for _, nalu := range nalus {
|
||||
if _, err := currentVideoFile.Write([]byte{0x00, 0x00, 0x00, 0x01}); err != nil {
|
||||
log.Printf("Ошибка записи префикса: %v", err)
|
||||
}
|
||||
if _, err := currentVideoFile.Write(nalu); err != nil {
|
||||
log.Printf("Ошибка записи NALU: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
case *format.G711:
|
||||
samples, err := decoderG711.Decode(pkt)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка декодирования G711: %v", err)
|
||||
return
|
||||
}
|
||||
fileMu.Lock()
|
||||
defer fileMu.Unlock()
|
||||
if currentAudioFile != nil {
|
||||
if _, err := currentAudioFile.Write(samples); err != nil {
|
||||
log.Printf("Ошибка записи аудио: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Запуск воспроизведения
|
||||
_, err = client.Play(nil)
|
||||
if err != nil {
|
||||
log.Fatalln("Ошибка запуска воспроизведения:", err)
|
||||
}
|
||||
|
||||
// Параметры записи
|
||||
period := time.Hour
|
||||
|
||||
// Ожидание начала следующего часа
|
||||
now := time.Now()
|
||||
nextHour := now.Truncate(time.Hour).Add(time.Hour)
|
||||
waitDuration := nextHour.Sub(now)
|
||||
fmt.Printf("Ожидание до начала записи: %v\n", waitDuration)
|
||||
time.Sleep(waitDuration)
|
||||
|
||||
// Создаем начальные файлы
|
||||
initialTimestamp := time.Now().Format("15-04_02-01-2006")
|
||||
videoFilename := initialTimestamp + ".h264"
|
||||
audioFilename := initialTimestamp + ".pcm"
|
||||
|
||||
fileVideo, err := os.Create(videoFilename)
|
||||
if err != nil {
|
||||
log.Fatalln("Ошибка создания видеофайла:", err)
|
||||
}
|
||||
fileAudio, err := os.Create(audioFilename)
|
||||
if err != nil {
|
||||
log.Fatalln("Ошибка создания аудиофайла:", err)
|
||||
}
|
||||
// Записываем SPS и PPS в начале видеофайла, если они заданы
|
||||
if len(h264Format.SPS) > 0 {
|
||||
fileVideo.Write([]byte{0x00, 0x00, 0x00, 0x01})
|
||||
fileVideo.Write(h264Format.SPS)
|
||||
}
|
||||
if len(h264Format.PPS) > 0 {
|
||||
fileVideo.Write([]byte{0x00, 0x00, 0x00, 0x01})
|
||||
fileVideo.Write(h264Format.PPS)
|
||||
}
|
||||
fileMu.Lock()
|
||||
currentVideoFile = fileVideo
|
||||
currentAudioFile = fileAudio
|
||||
fileMu.Unlock()
|
||||
|
||||
// Используем тикер для периодической ротации файлов без остановки записи
|
||||
ticker := time.NewTicker(period)
|
||||
defer ticker.Stop()
|
||||
|
||||
// Горутина, отвечающая за смену файлов
|
||||
go func() {
|
||||
for range ticker.C {
|
||||
// Открываем новые файлы заранее, чтобы запись шла непрерывно
|
||||
newTimestamp := time.Now().Format("15-04_02-01-2006")
|
||||
newVideoFilename := newTimestamp + ".h264"
|
||||
newAudioFilename := newTimestamp + ".pcm"
|
||||
|
||||
newVideoFile, err := os.Create(newVideoFilename)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка создания видеофайла для фрагмента %d: %v", newTimestamp, err)
|
||||
continue
|
||||
}
|
||||
newAudioFile, err := os.Create(newAudioFilename)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка создания аудиофайла для фрагмента %d: %v", newTimestamp, err)
|
||||
newVideoFile.Close()
|
||||
continue
|
||||
}
|
||||
// Записываем SPS/PPS в новый видеофайл
|
||||
if len(h264Format.SPS) > 0 {
|
||||
newVideoFile.Write([]byte{0x00, 0x00, 0x00, 0x01})
|
||||
newVideoFile.Write(h264Format.SPS)
|
||||
}
|
||||
if len(h264Format.PPS) > 0 {
|
||||
newVideoFile.Write([]byte{0x00, 0x00, 0x00, 0x01})
|
||||
newVideoFile.Write(h264Format.PPS)
|
||||
}
|
||||
|
||||
// Переключаемся на новые файлы
|
||||
fileMu.Lock()
|
||||
oldVideoFile := currentVideoFile
|
||||
oldAudioFile := currentAudioFile
|
||||
oldVideoFilename := videoFilename
|
||||
oldAudioFilename := audioFilename
|
||||
|
||||
currentVideoFile = newVideoFile
|
||||
currentAudioFile = newAudioFile
|
||||
// Обновляем имена для следующей итерации
|
||||
videoFilename = newVideoFilename
|
||||
audioFilename = newAudioFilename
|
||||
fileMu.Unlock()
|
||||
|
||||
// Закрываем старые файлы и запускаем обработку (слияние с аудио) в отдельной горутине
|
||||
oldVideoFile.Close()
|
||||
oldAudioFile.Close()
|
||||
|
||||
// Передаем значения переменных в замыкание, чтобы избежать их изменения
|
||||
go func(vFilename, aFilename string, newTimestamp string) {
|
||||
muxedFilename := strings.Replace(vFilename, ".h264", ".mp4", 1)
|
||||
cmd := exec.Command("ffmpeg",
|
||||
"-y",
|
||||
"-fflags", "+genpts",
|
||||
"-r", "25",
|
||||
"-f", "h264", "-i", vFilename,
|
||||
"-f", "s16le", "-ar", "8000", "-ac", "1", "-i", aFilename,
|
||||
"-filter_complex", "[1:a]atempo=0.5[aud]",
|
||||
"-map", "0:v",
|
||||
"-map", "[aud]",
|
||||
"-c:v", "copy",
|
||||
"-bsf:v", "dump_extra",
|
||||
"-c:a", "aac",
|
||||
muxedFilename,
|
||||
)
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Printf("Ошибка при объединении фрагментов: %v", err)
|
||||
} else {
|
||||
log.Printf("Фрагменты объединены в файл %s", muxedFilename)
|
||||
}
|
||||
}(oldVideoFilename, oldAudioFilename, newTimestamp)
|
||||
}
|
||||
}()
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
wg.Wait()
|
||||
}
|
23
writer/go.mod
Normal file
23
writer/go.mod
Normal file
@ -0,0 +1,23 @@
|
||||
module writer
|
||||
|
||||
go 1.23.6
|
||||
|
||||
require (
|
||||
github.com/bluenviron/gortsplib/v4 v4.12.3
|
||||
github.com/pion/rtp v1.8.11
|
||||
github.com/xfrr/goffmpeg v1.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go v1.55.6 // indirect
|
||||
github.com/bluenviron/mediacommon v1.14.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/rtcp v1.2.15 // indirect
|
||||
github.com/pion/sdp/v3 v3.0.10 // indirect
|
||||
github.com/u2takey/ffmpeg-go v0.5.0 // indirect
|
||||
github.com/u2takey/go-utils v0.3.1 // indirect
|
||||
golang.org/x/net v0.34.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
)
|
82
writer/go.sum
Normal file
82
writer/go.sum
Normal file
@ -0,0 +1,82 @@
|
||||
github.com/aws/aws-sdk-go v1.38.20/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.55.6 h1:cSg4pvZ3m8dgYcgqB97MrcdjUmZ1BeMYKUxMMB89IPk=
|
||||
github.com/aws/aws-sdk-go v1.55.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||
github.com/bluenviron/gortsplib/v4 v4.12.3 h1:3EzbyGb5+MIOJQYiWytRegFEP4EW5paiyTrscQj63WE=
|
||||
github.com/bluenviron/gortsplib/v4 v4.12.3/go.mod h1:SkZPdaMNr+IvHt2PKRjUXxZN6FDutmSZn4eT0GmF0sk=
|
||||
github.com/bluenviron/mediacommon v1.14.0 h1:lWCwOBKNKgqmspRpwpvvg3CidYm+XOc2+z/Jw7LM5dQ=
|
||||
github.com/bluenviron/mediacommon v1.14.0/go.mod h1:z5LP9Tm1ZNfQV5Co54PyOzaIhGMusDfRKmh42nQSnyo=
|
||||
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/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/panjf2000/ants/v2 v2.4.2/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A=
|
||||
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.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo=
|
||||
github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0=
|
||||
github.com/pion/rtp v1.8.11 h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk=
|
||||
github.com/pion/rtp v1.8.11/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4=
|
||||
github.com/pion/sdp/v3 v3.0.10 h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA=
|
||||
github.com/pion/sdp/v3 v3.0.10/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/u2takey/ffmpeg-go v0.5.0 h1:r7d86XuL7uLWJ5mzSeQ03uvjfIhiJYvsRAJFCW4uklU=
|
||||
github.com/u2takey/ffmpeg-go v0.5.0/go.mod h1:ruZWkvC1FEiUNjmROowOAps3ZcWxEiOpFoHCvk97kGc=
|
||||
github.com/u2takey/go-utils v0.3.1 h1:TaQTgmEZZeDHQFYfd+AdUT1cT4QJgJn/XVPELhHw4ys=
|
||||
github.com/u2takey/go-utils v0.3.1/go.mod h1:6e+v5vEZ/6gu12w/DC2ixZdZtCrNokVxD0JUklcqdCs=
|
||||
github.com/xfrr/goffmpeg v1.0.0 h1:trxuLNb9ys50YlV7gTVNAII9J0r00WWqCGTE46Gc3XU=
|
||||
github.com/xfrr/goffmpeg v1.0.0/go.mod h1:zjLRiirHnip+/hVAT3lVE3QZ6SGynr0hcctUMNNISdQ=
|
||||
gocv.io/x/gocv v0.25.0/go.mod h1:Rar2PS6DV+T4FL+PM535EImD/h13hGVaHhnCu1xarBs=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
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=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/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/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
Loading…
x
Reference in New Issue
Block a user