feat: 适配livegbs stream/info接口

This commit is contained in:
ydajiang
2025-08-29 15:37:15 +08:00
parent eeaeee14d5
commit 6ce491445d
2 changed files with 175 additions and 0 deletions

153
api.go
View File

@@ -8,6 +8,7 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/lkmio/avformat/utils" "github.com/lkmio/avformat/utils"
"github.com/lkmio/lkm/flv" "github.com/lkmio/lkm/flv"
"github.com/lkmio/lkm/gb28181"
"github.com/lkmio/lkm/hls" "github.com/lkmio/lkm/hls"
"github.com/lkmio/lkm/log" "github.com/lkmio/lkm/log"
"github.com/lkmio/lkm/rtc" "github.com/lkmio/lkm/rtc"
@@ -132,6 +133,8 @@ func startApiServer(addr string) {
runtime.GC() runtime.GC()
}) })
apiServer.router.HandleFunc("/api/v1/stream/info", apiServer.OnStreamInfo)
apiServer.router.PathPrefix("/web/").Handler(http.StripPrefix("/web/", http.FileServer(http.Dir("./web")))) apiServer.router.PathPrefix("/web/").Handler(http.StripPrefix("/web/", http.FileServer(http.Dir("./web"))))
http.Handle("/", apiServer.router) http.Handle("/", apiServer.router)
@@ -497,3 +500,153 @@ func (api *ApiServer) OnSinkClose(v *IDS, w http.ResponseWriter, r *http.Request
httpResponseOK(w, nil) httpResponseOK(w, nil)
} }
func (api *ApiServer) OnStreamInfo(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("streamid")
source := stream.SourceManager.Find(id)
if source == nil || !source.IsCompleted() || source.IsClosed() {
return
}
tracks := source.OriginTracks()
if len(tracks) < 1 {
return
}
var deviceId string
var channelId string
split := strings.Split(id, "/")
if len(split) < 2 {
return
}
deviceId = split[0]
channelId = split[1]
if len(split[1]) >= 20 {
channelId = split[1][:20]
}
var transport string
if stream.SourceType28181 == source.GetType() {
if gb28181.SetupUDP != source.(gb28181.GBSource).SetupType() {
transport = "TCP"
} else {
transport = "UDP"
}
}
var token string
cookie, err := r.Cookie("token")
if err == nil {
token = cookie.Value
}
urls := stream.GetStreamPlayUrlsMap(id)
liveGBSUrls := make(map[string]string)
for streamName, url := range urls {
url += "?stream_token=" + token
// 兼容livegbs前端播放webrtc
if streamName == "rtc" {
if strings.HasPrefix(url, "http") {
url = strings.Replace(url, "http", "webrtc", 1)
} else if strings.HasPrefix(url, "https") {
url = strings.Replace(url, "https", "webrtcs", 1)
}
url += "&wf=livegbs"
}
liveGBSUrls[streamName] = url
}
statistics := source.GetBitrateStatistics()
response := struct {
AudioEnable bool `json:"AudioEnable"`
CDN string `json:"CDN"`
CascadeSize int `json:"CascadeSize"`
ChannelID string `json:"ChannelID"`
ChannelName string `json:"ChannelName"`
CloudRecord bool `json:"CloudRecord"`
DecodeSize int `json:"DecodeSize"`
DeviceID string `json:"DeviceID"`
Duration int `json:"Duration"`
FLV string `json:"FLV"`
HLS string `json:"HLS"`
InBitRate int `json:"InBitRate"`
InBytes int `json:"InBytes"`
NumOutputs int `json:"NumOutputs"`
Ondemand bool `json:"Ondemand"`
OutBytes int `json:"OutBytes"`
RTMP string `json:"RTMP"`
RTPCount int `json:"RTPCount"`
RTPLostCount int `json:"RTPLostCount"`
RTPLostRate int `json:"RTPLostRate"`
RTSP string `json:"RTSP"`
RecordStartAt string `json:"RecordStartAt"`
RelaySize int `json:"RelaySize"`
SMSID string `json:"SMSID"`
SnapURL string `json:"SnapURL"`
SourceAudioCodecName string `json:"SourceAudioCodecName"`
SourceAudioSampleRate int `json:"SourceAudioSampleRate"`
SourceVideoCodecName string `json:"SourceVideoCodecName"`
SourceVideoFrameRate int `json:"SourceVideoFrameRate"`
SourceVideoHeight int `json:"SourceVideoHeight"`
SourceVideoWidth int `json:"SourceVideoWidth"`
StartAt string `json:"StartAt"`
StreamID string `json:"StreamID"`
Transport string `json:"Transport"`
VideoFrameCount int `json:"VideoFrameCount"`
WEBRTC string `json:"WEBRTC"`
WS_FLV string `json:"WS_FLV"`
}{
AudioEnable: true,
CDN: "",
CascadeSize: 0,
ChannelID: channelId,
ChannelName: "",
CloudRecord: false,
DecodeSize: 0,
DeviceID: deviceId,
Duration: int(time.Since(source.CreateTime()).Seconds()),
FLV: liveGBSUrls["flv"],
HLS: liveGBSUrls["hls"],
InBitRate: statistics.PreviousSecond() * 8 / 1024,
InBytes: int(statistics.Total()),
NumOutputs: 0,
Ondemand: true,
OutBytes: 0,
RTMP: liveGBSUrls["rtmp"],
RTPCount: 0,
RTPLostCount: 0,
RTPLostRate: 0,
RTSP: liveGBSUrls["rtsp"],
RecordStartAt: "",
RelaySize: 0,
SMSID: "",
SnapURL: "",
SourceVideoFrameRate: 0,
StartAt: source.CreateTime().Format("2006-01-02 15:04:05"),
StreamID: id,
Transport: transport,
VideoFrameCount: 0,
WEBRTC: liveGBSUrls["rtc"],
WS_FLV: liveGBSUrls["ws_flv"],
}
for _, track := range tracks {
if utils.AVMediaTypeAudio == track.Stream.MediaType {
response.SourceAudioCodecName = track.Stream.CodecID.String()
response.SourceAudioSampleRate = track.Stream.AudioConfig.SampleRate
} else if utils.AVMediaTypeVideo == track.Stream.MediaType {
response.SourceVideoCodecName = track.Stream.CodecID.String()
// response.SourceVideoFrameRate
if track.Stream.CodecParameters != nil {
response.SourceVideoWidth = track.Stream.CodecParameters.Width()
response.SourceVideoHeight = track.Stream.CodecParameters.Height()
}
}
}
httpResponseJson(w, &response)
}

View File

@@ -220,6 +220,28 @@ func GetStreamPlayUrls(source string) []string {
return urls return urls
} }
func GetStreamPlayUrlsMap(source string) map[string]string {
urls := GetStreamPlayUrls(source)
playUrlMap := make(map[string]string)
for _, url := range urls {
if strings.HasPrefix(url, "ws") {
playUrlMap["ws_flv"] = url
} else if strings.HasSuffix(url, ".flv") {
playUrlMap["flv"] = url
} else if strings.HasSuffix(url, ".m3u8") {
playUrlMap["hls"] = url
} else if strings.HasSuffix(url, ".rtc") {
playUrlMap["rtc"] = url
} else if strings.HasPrefix(url, "rtmp") {
playUrlMap["rtmp"] = url
} else if strings.HasPrefix(url, "rtsp") {
playUrlMap["rtsp"] = url
}
}
return playUrlMap
}
// DumpStream2File 保存推流到文件, 用4字节帧长分割 // DumpStream2File 保存推流到文件, 用4字节帧长分割
func DumpStream2File(sourceType SourceType, conn net.Conn, data []byte) { func DumpStream2File(sourceType SourceType, conn net.Conn, data []byte) {
path := fmt.Sprintf("dump/%s-%s", sourceType.String(), conn.RemoteAddr().String()) path := fmt.Sprintf("dump/%s-%s", sourceType.String(), conn.RemoteAddr().String())