>백엔드 개발 >Golang >golang rtsp를 http로

golang rtsp를 http로

WBOY
WBOY원래의
2023-05-10 17:46:37966검색

인터넷 기술의 지속적인 발전과 네트워크 애플리케이션의 인기로 인해 비디오 스트리밍 기술이 점차 널리 주목을 받고 있습니다. 비디오 스트리밍 기술에서 RTSP는 일반적으로 사용되는 스트리밍 미디어 전송 프로토콜로, 이를 통해 사용자는 네트워크에서 오디오 및 비디오 데이터를 전송하고 재생할 수 있습니다. 그러나 RTSP 프로토콜은 전송 과정에서 TCP 프로토콜을 사용하기 때문에 전송 속도가 상대적으로 느리고 점유 대역폭이 상대적으로 높아 사용자의 비디오 시청 경험에 일정한 영향을 미칩니다. 이 문제를 해결하기 위해 RTSP 스트림을 HTTP 스트림으로 변환하는 방법을 사용할 수 있습니다. 이를 통해 대역폭을 절약하고 전송 속도를 높일 수 있습니다. 이 기사에서는 golang을 사용하여 rtsp를 http로 변환하는 프로세스를 구현하는 방법을 소개합니다.

1. golang을 사용하여 RTSP를 HTTP로 구현

RTSP를 HTTP로 구현하기 전에 먼저 RTSP와 HTTP의 차이점을 이해해야 합니다. RTSP 프로토콜은 스트리밍 미디어 전송 프로토콜의 제어 부분을 구현해야 하지만 HTTP 프로토콜은 정적 페이지 전송과 데이터 전송을 구현합니다. 따라서 RTSP 스트림을 HTTP 스트림으로 변환하려면 제어 부분과 HTTP 정적 페이지의 전송을 구현하기 위해 중간 계층을 추가해야 합니다.

Golang은 효율적이고 간단하며 안정적이며 동시성이 높은 프로그래밍 언어로 실시간 오디오 및 비디오 스트리밍 데이터를 처리하는 데 매우 적합합니다. 따라서 우리는 RTSP를 HTTP로 변환하는 프로세스를 구현하기 위해 golang을 사용하기로 결정했습니다.

먼저 RTSP 프로토콜의 구문 분석 및 처리를 구현하려면 golang의 라이브러리를 사용해야 합니다. golang에는 RTSP 프로토콜의 구문 분석 및 처리를 구현하는 "gosip"이라는 타사 라이브러리가 있습니다. 이 라이브러리를 사용하여 RTSP를 HTTP로 변환하는 프로세스를 구현할 수 있습니다. 또한 HTTP 프로토콜 전송을 구현하려면 golang의 HTTP 라이브러리를 사용해야 합니다.

구체적인 구현 단계는 다음과 같습니다.

  1. 먼저 gosip 라이브러리를 사용하여 RTSP 프로토콜의 구문 분석 및 처리를 구현합니다.
import (
    "github.com/gorilla/mux"
    "github.com/nareix/srtcp"
    "github.com/nareix/udp"
    "github.com/nareix/webrtc"
    "github.com/nareix/xtcp"
    "github.com/nareix/joy4/format"
    "github.com/nareix/joy4/format/ts"
    "github.com/nareix/joy4/av"
    "github.com/nareix/joy4/container/rtp"
    "github.com/nareix/joy4/av/pubsub"
    "github.com/nareix/joy4/cgo/ffmpeg"
    "github.com/nareix/joy4/av/pktque"
    "net/http"
    "io"
    "fmt"
    "bytes"
    "strconv"
)

...

// 使用gosip库解析RTSP请求
func processRTSP(rtspRequest io.ReadWriteCloser, pubsub1 *pubsub.PubSub, aacWrite io.WriteCloser, h264Write io.WriteCloser) {
    sessionHandle := func(s *rtsp.Session) {
        p, err := s.Streams()
        checkError(err)

        var vtrack av.CodecData
        var atracks []av.CodecData
        for _, vi := range p {
            switch vi.Type().(type) {
            case av.H264CodecData:
                vtrack = vi.(av.H264CodecData)
                break
            case av.AACCodecData:
                atracks = append(atracks, vi.(av.AACCodecData))
                break
            }
        }

        var streamDialers []av.MuxCloser
        var streamWriters []av.MuxCloser

        // 创建H264的PubSub并添加到H264 Pub集
        H264Pub := pubsub.NewSimpleMuxer(100)
        streamDialers = append(streamDialers, H264Pub)
        go func() {
            H264Out := <-H264Pub.Out
            H264Outs, err := rtp.Encode(H264Out, vtrack.(av.VideoCodecData).Sdp())
            checkError(err)
            defer H264Outs.Close()
            n, err := s.WriteInterleaved(H264Outs)
            checkError(err)
            fmt.Println("Sent", n, "bytes. H264")
        }()

        // 创建AAC的PubSub并添加到AAC Pub集
        AACPubs := make([]*pubsub.PubSub, len(atracks))
        for i, atrack := range atracks {
            AACPubs[i] = pubsub.NewSimpleMuxer(100)
            streamDialers = append(streamDialers, AACPubs[i])
            go func(atrack av.CodecData, AACPubs1 *pubsub.PubSub) {
                out := <-AACPubs1.Out
                aacOut, _ := atrack.NewMuxer(out)
                defer aacOut.Close()

                outs, err := rtp.Encode(aacOut, atrack.(av.AudioCodecData).Sdp())
                checkError(err)
                defer outs.Close()
                n, err := s.WriteInterleaved(outs)
                checkError(err)
                fmt.Println("Sent", n, "bytes. Audio")
            }(atrack, AACPubs[i])
        }

        // 打开相应的转换器
        if aacWrite != nil {
            streamWriters = append(streamWriters, aacWrite)
            pubAACOut := make(chan []byte)
            AACPubs[0].Out <- pubAACOut
            go func() { // 把音频包推送到channel,再写到文件 
                for {
                    samples := <-pubAACOut
                    _, err := aacWrite.Write(samples)
                    checkError(err)
                }
            }()
        }
        if h264Write != nil {
            streamWriters = append(streamWriters, h264Write)
            H264Pub.Out <- h264Write
        }

        // 等待停止
        <-s.Done()
        for _, dialer := range streamDialers {
            fmt.Println("Closing dialer")
            dialer.Close()
        }
        for _, writer := range streamWriters {
            fmt.Println("Closing writer")
            writer.Close()
        }
    }

    for {
        req, err := rtsp.NewRequest()
        checkError(err)
        s, err := rtsp.NewSession(req, rtspRequest)
        if err != nil {
            fmt.Println(err)
            break
        }
        sessionHandle(s)
    }
}
  1. HTTP 라이브러리를 사용하여 HTTP 프로토콜을 구현하고 전송합니다.
...

// 使用HTTP协议请求推送的HLS流
func processHTTP(w http.ResponseWriter, r *http.Request) {
    ctx := &av.Context{Logger: logger}

    fmt.Println("New connection")
    defer fmt.Println("Closing write")

    v := mux.Vars(r)
    streamName := v["name"]

    if r.Method == "GET" {
        fmt.Println("HTTP GET request received...")

        segSeq := 0
        for {
            writer := NewHTTPStreamer(streamName, segSeq, w)
            segSeq++
            pubsub1 := pubsub.NewSimpleMuxer(100)

            // 创建http请求推送流着音视频流
            go func() {
                defer writer.Close()

                fmt.Println("Connected HTTP Writer. Waiting for output.")

                for {
                    Out := <-pubsub1.Out
                    fmt.Println("Received output")
                    ctx := &av.Context{Logger: logger, Write: writer}
                    fmt.Println(ctx)
                    defer ctx.Flush()
                    stream := Out[0]
                    fmt.Println(stream)
                    _ = avutil.CopyPackets(ctx, stream)
                }
            }()
            aacWrite, h264Write := getHLS(path.Join(videoTempDir, streamName), segSeq)
            processRTSP(NewRTSPReader(streamName), pubsub1, aacWrite, h264Write)
        }
    }
}

// 实现HTTP音视频流
func NewHTTPStreamer(base string, sn int, w http.ResponseWriter) *HTTPStreamer {
    str := fmt.Sprintf("%v/%v-%d.ts", videoTempDir, base, sn)
    f, _ := os.Create(str)
    return &HTTPStreamer{Writer: f, ResponseWriter: w}
}

...
  1. 마지막으로 RTSP 요청을 HTTP 응답과 연결하여 RTSP를 HTTP로 변환하는 프로세스를 실현합니다.
...

// 连接RTSP请求和HTTP响应
func streamInvoke(w http.ResponseWriter, r *http.Request) {
    fmt.Println(r.URL.Path)
    if strings.HasPrefix(r.URL.Path, "/stream/") {
        processHTTP(w, r)
    } else if strings.HasPrefix(r.URL.Path, "/hls/") {
        processHLS(w, r)
    } else {
        fmt.Println(r.URL.Path)
        w.WriteHeader(404)
    }
}

...

위는 RTSP를 HTTP로 변환하는 과정을 golang을 통해 구현하는 구체적인 구현 방법입니다. RTSP 스트림을 HTTP 스트림으로 변환하면 비디오 미디어 전송이 더 빠르고 효율적이 되어 사용자의 시청 경험이 향상됩니다.

위 내용은 golang rtsp를 http로의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.