From dc2ab5fcc0083bd3b953a606b4757db8860f95cd Mon Sep 17 00:00:00 2001 From: Alexey Khit Date: Mon, 28 Aug 2023 19:30:34 +0300 Subject: [PATCH] Add support TP-Link Kasa Spot KC401 #545 --- .gitignore | 5 ++--- internal/http/http.go | 28 ++++++++++++++++++++++++--- pkg/multipart/producer.go | 40 +++++++++++++++++++-------------------- 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index f0f61075..75516f34 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ - .idea/ - .tmp/ go2rtc.yaml - go2rtc.json + +0_test.go diff --git a/internal/http/http.go b/internal/http/http.go index a39ca4bd..bd6fc265 100644 --- a/internal/http/http.go +++ b/internal/http/http.go @@ -2,8 +2,10 @@ package http import ( "errors" + "io" "net" "net/http" + "net/http/httputil" "net/url" "strings" @@ -33,12 +35,17 @@ func handleHTTP(rawURL string) (core.Producer, error) { return nil, err } + var chunked bool + if rawQuery != "" { query := streams.ParseQuery(rawQuery) + for _, header := range query["header"] { key, value, _ := strings.Cut(header, ":") req.Header.Add(key, strings.TrimSpace(value)) } + + chunked = query.Get("chunked") == "1" } res, err := tcp.Do(req) @@ -61,18 +68,33 @@ func handleHTTP(rawURL string) (core.Producer, error) { ext = req.URL.Path[i+1:] } + var rd io.ReadCloser + + // support buggy clients, like TP-Link cameras with HTTP/1.0 chunked encoding + if chunked { + rd = struct { + io.Reader + io.Closer + }{ + httputil.NewChunkedReader(res.Body), + res.Body, + } + } else { + rd = res.Body + } + switch { case ct == "image/jpeg": return mjpeg.NewClient(res), nil case ct == "multipart/x-mixed-replace": - return multipart.Open(res.Body) + return multipart.Open(rd) case ct == "application/vnd.apple.mpegurl" || ext == "m3u8": - return hls.OpenURL(req.URL, res.Body) + return hls.OpenURL(req.URL, rd) } - return magic.Open(res.Body) + return magic.Open(rd) } func handleTCP(rawURL string) (core.Producer, error) { diff --git a/pkg/multipart/producer.go b/pkg/multipart/producer.go index 6766a885..f77061ee 100644 --- a/pkg/multipart/producer.go +++ b/pkg/multipart/producer.go @@ -11,6 +11,7 @@ import ( "time" "github.com/AlexxIT/go2rtc/pkg/core" + "github.com/AlexxIT/go2rtc/pkg/h264" "github.com/AlexxIT/go2rtc/pkg/h264/annexb" "github.com/pion/rtp" ) @@ -166,11 +167,11 @@ func (c *Producer) probe() error { c.reader = bufio.NewReader(c.rd) }() - waitVideo := true - waitAudio := true + waitVideo, waitAudio := true, true + timeout := time.Now().Add(core.ProbeTimeout) - for waitVideo || waitAudio { - header, _, err := c.next() + for (waitVideo || waitAudio) && time.Now().Before(timeout) { + header, body, err := c.next() if err != nil { return err } @@ -181,26 +182,23 @@ func (c *Producer) probe() error { switch ct { case MimeVideo: if !waitVideo { - return nil - } - - media = &core.Media{ - Kind: core.KindVideo, - Direction: core.DirectionRecvonly, - Codecs: []*core.Codec{ - { - Name: core.CodecH264, - ClockRate: 90000, - PayloadType: core.PayloadTypeRAW, - }, - }, + continue } waitVideo = false + body = annexb.EncodeToAVCC(body, false) + codec := h264.AVCCToCodec(body) + media = &core.Media{ + Kind: core.KindVideo, + Direction: core.DirectionRecvonly, + Codecs: []*core.Codec{codec}, + } + case MimeG711U: if !waitAudio { - return nil + continue } + waitAudio = false media = &core.Media{ Kind: core.KindAudio, @@ -212,9 +210,11 @@ func (c *Producer) probe() error { }, }, } - waitAudio = false default: + waitVideo = false + waitAudio = false + media = &core.Media{ Kind: core.KindVideo, Direction: core.DirectionRecvonly, @@ -226,8 +226,6 @@ func (c *Producer) probe() error { }, }, } - waitVideo = false - waitAudio = false } c.Medias = append(c.Medias, media)