赞
踩
rtsp-simple-server
是RTSP / RTMP / LL-HLS 服务器和代理,允许读取、发布和代理视频和音频流。
目前支持的流有:RTSP
,RTMP
,HLS
。
github的地址在这里。
安装非常的简单,采用docker的方式:
docker run --rm -it -e RTSP_PROTOCOLS=tcp -p 8554:8554 -p 1935:1935 -p 8888:8888 aler9/rtsp-simple-server
启动流服务器,记住那里的ip地址,并把流推到服务器上。
ffmpeg.exe -re -i a.mp4 -vcodec h264 -acodec aac -f rtsp -rtsp_transport tcp rtsp://192.168.100.170:8554/mystream
我这里采用的是ffmpeg
把流推到服务器,服务器的地址为192.168.100.170,我们把它推到mystream
的目录下,接下来取流的方式就比较简单了,可以使用vlc进行播放。
vlc rtsp://192.168.100.170:8554/mystream
也可以用直接拉流,存为视频:
ffmpeg -i rtsp://192.168.100.170:8554/mystream -c copy output.mp4
这样就完成了一次取流和拉流的功能,可能大家对这种流媒体并不熟悉,但是流媒体编程也是一个中友好的方向,下面简单看下代码过程。
rtsp-simple-server
使用的是go语言编写,如果学着编写一款服务器的软件,可以用这款作为入门的代码。
rtsp的授权过程:
func (c *rtspConn) authenticate( pathName string, pathIPs []fmt.Stringer, pathUser conf.Credential, pathPass conf.Credential, isPublishing bool, req *base.Request, query string, ) error { if c.externalAuthenticationURL != "" { username := "" password := "" var auth headers.Authorization err := auth.Unmarshal(req.Header["Authorization"]) if err == nil && auth.Method == headers.AuthBasic { username = auth.BasicUser password = auth.BasicPass } err = externalAuth( c.externalAuthenticationURL, c.ip().String(), username, password, pathName, isPublishing, query) if err != nil { c.authFailures++ // VLC with login prompt sends 4 requests: // 1) without credentials // 2) with password but without username // 3) without credentials // 4) with password and username // therefore we must allow up to 3 failures if c.authFailures > 3 { return pathErrAuthCritical{ message: "unauthorized: " + err.Error(), response: &base.Response{ StatusCode: base.StatusUnauthorized, }, } } v := "IPCAM" return pathErrAuthNotCritical{ message: "unauthorized: " + err.Error(), response: &base.Response{ StatusCode: base.StatusUnauthorized, Header: base.Header{ "WWW-Authenticate": headers.Authenticate{ Method: headers.AuthBasic, Realm: &v, }.Marshal(), }, }, } } } if pathIPs != nil { ip := c.ip() if !ipEqualOrInRange(ip, pathIPs) { return pathErrAuthCritical{ message: fmt.Sprintf("IP '%s' not allowed", ip), response: &base.Response{ StatusCode: base.StatusUnauthorized, }, } } } if pathUser != "" { // reset authValidator every time the credentials change if c.authValidator == nil || c.authUser != string(pathUser) || c.authPass != string(pathPass) { c.authUser = string(pathUser) c.authPass = string(pathPass) c.authValidator = auth.NewValidator(string(pathUser), string(pathPass), c.authMethods) } err := c.authValidator.ValidateRequest(req) if err != nil { c.authFailures++ // VLC with login prompt sends 4 requests: // 1) without credentials // 2) with password but without username // 3) without credentials // 4) with password and username // therefore we must allow up to 3 failures if c.authFailures > 3 { return pathErrAuthCritical{ message: "unauthorized: " + err.Error(), response: &base.Response{ StatusCode: base.StatusUnauthorized, }, } } return pathErrAuthNotCritical{ response: &base.Response{ StatusCode: base.StatusUnauthorized, Header: base.Header{ "WWW-Authenticate": c.authValidator.Header(), }, }, } } // login successful, reset authFailures c.authFailures = 0 } return nil }
rtsp 的协议过程:
// OnDescribe implements gortsplib.ServerHandlerOnDescribe. func (s *rtspServer) OnDescribe(ctx *gortsplib.ServerHandlerOnDescribeCtx, ) (*base.Response, *gortsplib.ServerStream, error) { s.mutex.RLock() c := s.conns[ctx.Conn] s.mutex.RUnlock() return c.onDescribe(ctx) } // OnAnnounce implements gortsplib.ServerHandlerOnAnnounce. func (s *rtspServer) OnAnnounce(ctx *gortsplib.ServerHandlerOnAnnounceCtx) (*base.Response, error) { s.mutex.RLock() c := s.conns[ctx.Conn] se := s.sessions[ctx.Session] s.mutex.RUnlock() return se.onAnnounce(c, ctx) } // OnSetup implements gortsplib.ServerHandlerOnSetup. func (s *rtspServer) OnSetup(ctx *gortsplib.ServerHandlerOnSetupCtx) (*base.Response, *gortsplib.ServerStream, error) { s.mutex.RLock() c := s.conns[ctx.Conn] se := s.sessions[ctx.Session] s.mutex.RUnlock() return se.onSetup(c, ctx) } // OnPlay implements gortsplib.ServerHandlerOnPlay. func (s *rtspServer) OnPlay(ctx *gortsplib.ServerHandlerOnPlayCtx) (*base.Response, error) { s.mutex.RLock() se := s.sessions[ctx.Session] s.mutex.RUnlock() return se.onPlay(ctx) } // OnRecord implements gortsplib.ServerHandlerOnRecord. func (s *rtspServer) OnRecord(ctx *gortsplib.ServerHandlerOnRecordCtx) (*base.Response, error) { s.mutex.RLock() se := s.sessions[ctx.Session] s.mutex.RUnlock() return se.onRecord(ctx) } // OnPause implements gortsplib.ServerHandlerOnPause. func (s *rtspServer) OnPause(ctx *gortsplib.ServerHandlerOnPauseCtx) (*base.Response, error) { s.mutex.RLock() se := s.sessions[ctx.Session] s.mutex.RUnlock() return se.onPause(ctx) } // OnPacketRTP implements gortsplib.ServerHandlerOnPacket. func (s *rtspServer) OnPacketRTP(ctx *gortsplib.ServerHandlerOnPacketRTPCtx) { s.mutex.RLock() se := s.sessions[ctx.Session] s.mutex.RUnlock() se.onPacketRTP(ctx) }
这个就是相当于rtsp的简单过程了,如果想进行深入了解的话,可以从代码中获得。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。