| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- package system
- import (
- "fmt"
- "github.com/gin-gonic/gin"
- "go.uber.org/zap"
- "net/http"
- "os"
- "path/filepath"
- "server/global"
- "server/model/common/response"
- "server/service/stream"
- )
- // StreamApi API接口结构体
- type StreamApi struct{}
- var (
- StreamService = stream.NewStreamService()
- // HLS文件存储的相对路径(跨平台兼容)
- hlsBaseDir = filepath.Join("..\\", "server", "hls")
- )
- // StartStream 启动RTSP转HLS流
- // @Tags Stream
- // @Summary 启动RTSP转HLS流
- // @Security ApiKeyAuth
- // @accept application/json
- // @Produce application/json
- // @Param data body StartStreamRequest true "RTSP地址和流ID"
- // @Success 200 {object} response.Response{data=string} "返回HLS流地址"
- // @Router /stream/start [post]
- func (s *StreamApi) StartStream(c *gin.Context) {
- var req StartStreamRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- global.GVA_LOG.Error("参数验证失败", zap.Error(err))
- response.FailWithMessage("参数错误: "+err.Error(), c)
- return
- }
- hlsUrl, err := StreamService.StartStream(req.RTSPUrl, req.StreamID)
- if err != nil {
- global.GVA_LOG.Error("启动流转换失败", zap.Error(err))
- response.FailWithMessage(err.Error(), c)
- return
- }
- response.OkWithData(map[string]string{
- "hlsUrl": hlsUrl,
- }, c)
- }
- // StopStream 停止流转换
- // @Tags Stream
- // @Summary 停止流转换
- // @Security ApiKeyAuth
- // @accept application/json
- // @Produce application/json
- // @Param data body StopStreamRequest true "流ID"
- // @Success 200 {object} response.Response
- // @Router /stream/stop [post]
- func (s *StreamApi) StopStream(c *gin.Context) {
- var req StopStreamRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- global.GVA_LOG.Error("参数验证失败", zap.Error(err))
- response.FailWithMessage("参数错误: "+err.Error(), c)
- return
- }
- if err := StreamService.StopStream(req.StreamID); err != nil {
- global.GVA_LOG.Error("停止流转换失败", zap.Error(err))
- response.FailWithMessage(err.Error(), c)
- return
- }
- response.OkWithMessage("流已成功停止", c)
- }
- // PlayHLS 播放HLS流
- // @Tags Stream
- // @Summary 播放HLS流
- // @accept application/json
- // @Produce application/x-mpegURL
- // @Param streamId path string true "流ID"
- // @Param any path string true "m3u8或ts文件名"
- // @Success 200 {file} file "返回视频流文件"
- // @Router /stream/hls/{streamId}/{any} [get]
- func (s *StreamApi) PlayHLS(c *gin.Context) {
- streamId := c.Param("streamId")
- filePath := c.Param("any")
- // 构建完整的文件路径(跨平台兼容)
- fullPath := filepath.Join(hlsBaseDir, streamId, filePath)
- fmt.Println("fullPath:", fullPath)
- // 检查文件是否存在
- if _, err := os.Stat(fullPath); err != nil {
- global.GVA_LOG.Error("HLS文件不存在", zap.String("path", fullPath), zap.Error(err))
- c.JSON(http.StatusNotFound, gin.H{
- "code": 404,
- "msg": "HLS文件不存在: " + fullPath,
- })
- return
- }
- // 设置正确的Content-Type
- switch filepath.Ext(fullPath) {
- case ".m3u8":
- c.Header("Content-Type", "application/x-mpegURL")
- case ".ts":
- c.Header("Content-Type", "video/MP2T")
- default:
- c.Header("Content-Type", "application/octet-stream")
- }
- // 禁用缓存,支持断点续传
- c.Header("Cache-Control", "no-cache")
- c.Header("Accept-Ranges", "bytes")
- // 发送文件内容
- c.File(fullPath)
- }
- // GetStreamList 获取活跃流列表
- // @Tags Stream
- // @Summary 获取活跃流列表
- // @Security ApiKeyAuth
- // @accept application/json
- // @Produce application/json
- // @Success 200 {object} response.Response{data=[]string} "返回活跃流ID列表"
- // @Router /stream/list [get]
- func (s *StreamApi) GetStreamList(c *gin.Context) {
- list := StreamService.GetActiveStreams()
- response.OkWithData(list, c)
- }
- // 请求结构体定义
- type StartStreamRequest struct {
- RTSPUrl string `json:"rtspUrl" binding:"required"` // RTSP流地址
- StreamID string `json:"streamId" binding:"required"` // 流唯一标识
- }
- type StopStreamRequest struct {
- StreamID string `json:"streamId" binding:"required"` // 流唯一标识
- }
|