我想将给定的 RTSP 流 URL 从 IP 摄像机转换为 WebRTC 并在浏览器中显示。我完成了那部分,我想更改代码,可以使用 URL 参数(如 ?camera=camera01、?camera=camera02 等)更改 IP 摄像机。 RTSP URL 是硬编码的,无需担心。
Curranty 我像这样更改相机:http://127.0.0.1:8083/stream/player/Camera01 我想像这样更改相机:http://127.0.0.1:8088/stream/player?camera=Camera01
我该如何改变?
package main
import (
"encoding/json"
"log"
"net/http"
"os"
"sort"
"time"
"github.com/deepch/vdk/av"
webrtc "github.com/deepch/vdk/format/webrtcv3"
"github.com/gin-gonic/gin"
)
type JCodec struct {
Type string
}
func serveHTTP() {
gin.SetMode(gin.ReleaseMode)
router := gin.Default()
router.Use(CORSMiddleware())
if _, err := os.Stat("./web"); !os.IsNotExist(err) {
router.LoadHTMLGlob("web/templates/*")
router.GET("/", HTTPAPIServerIndex)
router.GET("/stream/player/:uuid", HTTPAPIServerStreamPlayer)
}
router.POST("/stream/receiver/:uuid", HTTPAPIServerStreamWebRTC)
router.GET("/stream/codec/:uuid", HTTPAPIServerStreamCodec)
router.POST("/stream", HTTPAPIServerStreamWebRTC2)
router.StaticFS("/static", http.Dir("web/static"))
err := router.Run(Config.Server.HTTPPort)
if err != nil {
log.Fatalln("Start HTTP Server error", err)
}
}
// HTTPAPIServerIndex index
func HTTPAPIServerIndex(c *gin.Context) {
_, all := Config.list()
if len(all) > 0 {
c.Header("Cache-Control", "no-cache, max-age=0, must-revalidate, no-store")
c.Header("Access-Control-Allow-Origin", "*")
c.Redirect(http.StatusMovedPermanently, "stream/player/"+all[0])
} else {
c.HTML(http.StatusOK, "index.tmpl", gin.H{
"port": Config.Server.HTTPPort,
"version": time.Now().String(),
})
}
}
// HTTPAPIServerStreamPlayer stream player
func HTTPAPIServerStreamPlayer(c *gin.Context) {
_, all := Config.list()
sort.Strings(all)
c.HTML(http.StatusOK, "player.tmpl", gin.H{
"port": Config.Server.HTTPPort,
"suuid": c.Param("uuid"),
"suuidMap": all,
"version": time.Now().String(),
})
}
// HTTPAPIServerStreamCodec stream codec
func HTTPAPIServerStreamCodec(c *gin.Context) {
if Config.ext(c.Param("uuid")) {
Config.RunIFNotRun(c.Param("uuid"))
codecs := Config.coGe(c.Param("uuid"))
if codecs == nil {
return
}
var tmpCodec []JCodec
for _, codec := range codecs {
if codec.Type() != av.H264 && codec.Type() != av.PCM_ALAW && codec.Type() != av.PCM_MULAW && codec.Type() != av.OPUS {
log.Println("Codec Not Supported WebRTC ignore this track", codec.Type())
continue
}
if codec.Type().IsVideo() {
tmpCodec = append(tmpCodec, JCodec{Type: "video"})
} else {
tmpCodec = append(tmpCodec, JCodec{Type: "audio"})
}
}
b, err := json.Marshal(tmpCodec)
if err == nil {
_, err = c.Writer.Write(b)
if err != nil {
log.Println("Write Codec Info error", err)
return
}
}
}
}
// HTTPAPIServerStreamWebRTC stream video over WebRTC
func HTTPAPIServerStreamWebRTC(c *gin.Context) {
if !Config.ext(c.PostForm("suuid")) {
log.Println("Stream Not Found")
return
}
Config.RunIFNotRun(c.PostForm("suuid"))
codecs := Config.coGe(c.PostForm("suuid"))
if codecs == nil {
log.Println("Stream Codec Not Found")
return
}
var AudioOnly bool
if len(codecs) == 1 && codecs[0].Type().IsAudio() {
AudioOnly = true
}
muxerWebRTC := webrtc.NewMuxer(webrtc.Options{ICEServers: Config.GetICEServers(), ICEUsername: Config.GetICEUsername(), ICECredential: Config.GetICECredential(), PortMin: Config.GetWebRTCPortMin(), PortMax: Config.GetWebRTCPortMax()})
answer, err := muxerWebRTC.WriteHeader(codecs, c.PostForm("data"))
if err != nil {
log.Println("WriteHeader", err)
return
}
_, err = c.Writer.Write([]byte(answer))
if err != nil {
log.Println("Write", err)
return
}
go func() {
cid, ch := Config.clAd(c.PostForm("suuid"))
defer Config.clDe(c.PostForm("suuid"), cid)
defer muxerWebRTC.Close()
var videoStart bool
noVideo := time.NewTimer(10 * time.Second)
for {
select {
case <-noVideo.C:
log.Println("noVideo")
return
case pck := <-ch:
if pck.IsKeyFrame || AudioOnly {
noVideo.Reset(10 * time.Second)
videoStart = true
}
if !videoStart && !AudioOnly {
continue
}
err = muxerWebRTC.WritePacket(pck)
if err != nil {
log.Println("WritePacket", err)
return
}
}
}
}()
}
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Credentials", "true")
c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization, x-access-token")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
c.Header("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
}
}
type Response struct {
Tracks []string `json:"tracks"`
Sdp64 string `json:"sdp64"`
}
type ResponseError struct {
Error string `json:"error"`
}
func HTTPAPIServerStreamWebRTC2(c *gin.Context) {
url := c.PostForm("url")
if _, ok := Config.Streams[url]; !ok {
Config.Streams[url] = StreamST{
URL: url,
OnDemand: true,
Cl: make(map[string]viewer),
}
}
Config.RunIFNotRun(url)
codecs := Config.coGe(url)
if codecs == nil {
log.Println("Stream Codec Not Found")
c.JSON(500, ResponseError{Error: Config.LastError.Error()})
return
}
muxerWebRTC := webrtc.NewMuxer(
webrtc.Options{
ICEServers: Config.GetICEServers(),
PortMin: Config.GetWebRTCPortMin(),
PortMax: Config.GetWebRTCPortMax(),
},
)
sdp64 := c.PostForm("sdp64")
answer, err := muxerWebRTC.WriteHeader(codecs, sdp64)
if err != nil {
log.Println("Muxer WriteHeader", err)
c.JSON(500, ResponseError{Error: err.Error()})
return
}
response := Response{
Sdp64: answer,
}
for _, codec := range codecs {
if codec.Type() != av.H264 &&
codec.Type() != av.PCM_ALAW &&
codec.Type() != av.PCM_MULAW &&
codec.Type() != av.OPUS {
log.Println("Codec Not Supported WebRTC ignore this track", codec.Type())
continue
}
if codec.Type().IsVideo() {
response.Tracks = append(response.Tracks, "video")
} else {
response.Tracks = append(response.Tracks, "audio")
}
}
c.JSON(200, response)
AudioOnly := len(codecs) == 1 && codecs[0].Type().IsAudio()
go func() {
cid, ch := Config.clAd(url)
defer Config.clDe(url, cid)
defer muxerWebRTC.Close()
var videoStart bool
noVideo := time.NewTimer(10 * time.Second)
for {
select {
case <-noVideo.C:
log.Println("noVideo")
return
case pck := <-ch:
if pck.IsKeyFrame || AudioOnly {
noVideo.Reset(10 * time.Second)
videoStart = true
}
if !videoStart && !AudioOnly {
continue
}
err = muxerWebRTC.WritePacket(pck)
if err != nil {
log.Println("WritePacket", err)
return
}
}
}
}()
}
从
/:uuid
中删除 /stream/player/:uuid
并将 c.Param("uuid")
替换为 c.Query("camera")
in HTTPAPIServerStreamPlayer()
功能。
然后点击http://127.0.0.1:8088/stream/player?camera=Camera01希望它能工作