ホームページ  >  記事  >  バックエンド開発  >  golang rtsp から http へ

golang rtsp から http へ

WBOY
WBOYオリジナル
2023-05-10 17:46:37946ブラウズ

インターネット技術の継続的な発展とネットワークアプリケーションの普及に伴い、ビデオストリーミング技術は徐々に広く注目を集めるようになりました。ビデオ ストリーミング テクノロジでは、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 を使用することにしました。

まず、golang のライブラリを使用して、RTSP プロトコルの解析と処理を実装する必要があります。 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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。