0


Github每日精选(第50期):RTSP / RTMP / LL-HLS 服务器rtsp-simple-server

rtsp-simple-server

rtsp-simple-server

是RTSP / RTMP / LL-HLS 服务器和代理,允许读取、发布和代理视频和音频流。

目前支持的流有:

RTSP

RTMP

HLS

在这里插入图片描述

github的地址在这里。

特征:

  • 将直播流发布到服务器
  • 从服务器读取实时流
  • 来自其他服务器或摄像机的代理流,始终或按需
  • 每个流可以有多个视频和音频轨道,用任何 RTP 兼容的编解码器编码,包括 H264、H265、VP8、- VP9、MPEG2、MP3、AAC、Opus、PCM、JPEG
  • 流会自动从一种协议转换为另一种协议。例如,可以使用 RTSP 发布流并使用 HLS 读取它
  • 在不同的路径中一次提供多个流
  • 对用户进行身份验证;使用内部或外部身份验证
  • 将阅读器重定向到其他 RTSP 服务器(负载平衡)
  • 通过 HTTP API 查询和控制服务器
  • 在不断开现有客户端的情况下重新加载配置(热重新加载)
  • 阅读 Prometheus 兼容的指标
  • 当客户端连接、断开、读取或发布流时运行外部命令
  • 与 Raspberry Pi 相机原生兼容
  • 与 Linux、Windows 和 macOS 兼容,不需要任何依赖项或解释器,它是单个可执行文件

安装

安装非常的简单,采用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 failuresif 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 changeif 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 failuresif 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}returnnil}

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的简单过程了,如果想进行深入了解的话,可以从代码中获得。

标签: 服务器 github 运维

本文转载自: https://blog.csdn.net/weixin_40425640/article/details/126603258
版权归原作者 go2coding 所有, 如有侵权,请联系我们删除。

“Github每日精选(第50期):RTSP / RTMP / LL-HLS 服务器rtsp-simple-server”的评论:

还没有评论