百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Java 监控直播流rtsp协议转rtmp、hls、httpflv协议返回浏览器

zhezhongyun 2025-02-21 16:16 63 浏览

Java 监控直播流rtsp协议转rtmp、hls、httpflv协议返回浏览器

目录

  • 一:了解音视频流协议:
  • 二:方案一 rtsp 转rtmp1、下载nginx + nginx-rtmp-module3、cmd 到nginx根目录启动nginx8、查摄像头的rtsp协议格式10、测试rtmp是否转换成功12、为什么放弃了用rtmp
  • 四:方案三rtsp 转httpflv(采用)1、安装nginx-flv-module4.1 采用java代码去执行ffmepg命令6、前端使用flv.js播放:

需求背景:

在做之前的项目的时候有一个对接摄像头实时播放的需求,由于我们摄像头的购买量不是很多,海康威视不给我们提供流媒体云服务器,所以需要我们自己去 一个去满足我们能在浏览器看到监控画面。项目源代码在以前公司没有拷贝就不能复习,最近又在准备面试,所以写了这个博客来复盘和扩展一下,由于我现在没有Liunx,我就用Windows来演示,生产环境还是要使用Liunx,下面这些操作在Liunx也是一样的流程,大家自行百度。

一:了解音视频流协议:

媒体流协议对比

协议

HttpFlv

RTMP

HLS

Dash

全称

FLASH VIDEO over HTTP

Real Time Message Protocol

HTTP Living Streaming


传输方式

HTTP长连接

TCP长连接

HTTP短连接

HTTP短连接

视频封装格式

FLV

FLV TAG

TS文件

Mp4

3gp

webm

原理

同 RTMP ,使用HTTP协议(80端口)

每个时刻的数据收到后立刻转发

集合一段时间的数据,生成TS切片文件(三片),并更新m3u8索引


延时

1~3秒

1~3秒

5~20秒(依切片情况)

数据分段

连续流

连续流

切片文件

切片文件

Html5播放

可通过HTML5解封包播放

(flv.js)

不支持

可通过HTML5解封包播放

(hls.js)

如果dash文件列表是MP4,

webm文件,可直接播放

其它

需要Flash技术支持,不支持多音频流、多视频流,不便于seek(即拖进度条)

跨平台支持较差,需要Flash技术支持

播放时需要多次请求,对于网络质量要求高


二:方案一 rtsp 转rtmp

1、下载nginx + nginx-rtmp-module

nginx:下载地址:
http://nginx-win.ecsds.eu/download/

nginx-rtmp-module:nginx 的扩展,安装后支持rtmp协议,下载地址:
https://github.com/arut/nginx-rtmp-module

解压nginx-rtmp-module到nginx根目录下,并修改其文件夹名为nginx-rtmp-module(原名为nginx-rtmp-module-master)

2、nginx配置文件

到nginx根目录下的conf目录下复制一份nginx-win.conf 重命名 nginx-win-rtmp.conf

nginx-win-rtmp.conf:

#user  nobody;
# multiple workers works !
worker_processes  2;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  8192;
    # max value 32768, nginx recycling connections+registry optimization = 
    #   this.value * 20 = max concurrent connections currently tested with one worker
    #   C1000K should be possible depending there is enough ram/cpu power
    # multi_accept on;
}

rtmp {
    server {
        listen 1935;
        chunk_size 4000;
		
        application live {
             live on;
             # 播放时进行回调,如果HttpRespone statusCode不等于200会断开
			 # on_play http://localhost:8081/auth;
        }
		
		application hls {
		     live on; 
		     # 开启hls切片
             hls on;
             # m3u8地址
			 hls_path html/hls;
			 # 一个切片多少秒
			 hls_fragment 8s;
			 # on_play http://localhost:8081/auth;
			 # on_publish http://localhost:8081/auth;
			 # on_done http://localhost:8081/auth;
        }
    }
}

http {
    #include      /nginx/conf/naxsi_core.rules;
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr:$remote_port - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

#     # loadbalancing PHP
#     upstream myLoadBalancer {
#         server 127.0.0.1:9001 weight=1 fail_timeout=5;
#         server 127.0.0.1:9002 weight=1 fail_timeout=5;
#         server 127.0.0.1:9003 weight=1 fail_timeout=5;
#         server 127.0.0.1:9004 weight=1 fail_timeout=5;
#         server 127.0.0.1:9005 weight=1 fail_timeout=5;
#         server 127.0.0.1:9006 weight=1 fail_timeout=5;
#         server 127.0.0.1:9007 weight=1 fail_timeout=5;
#         server 127.0.0.1:9008 weight=1 fail_timeout=5;
#         server 127.0.0.1:9009 weight=1 fail_timeout=5;
#         server 127.0.0.1:9010 weight=1 fail_timeout=5;
#         least_conn;
#     }

    sendfile        off;
    #tcp_nopush     on;

    server_names_hash_bucket_size 128;

## Start: Timeouts ##
    client_body_timeout   10;
    client_header_timeout 10;
    keepalive_timeout     30;
    send_timeout          10;
    keepalive_requests    10;
## End: Timeouts ##

    #gzip  on;

    server {
        listen       5080;
        server_name  localhost;


        location /stat {
            rtmp_stat all;
            rtmp_stat_stylesheet stat.xsl;
        }
        location /stat.xsl {
            root nginx-rtmp-module/;
        }
        location /control {
            rtmp_control all;
        }
		
		location /hls {
            # Serve HLS fragments
            types {
                application/vnd.apple.mpegurl m3u8;
                video/mp2t ts;
            }
            expires -1;
            add_header Access-Control-Allow-Origin *;
        }

        #charset koi8-r;
        #access_log  logs/host.access.log  main;

        ## Caching Static Files, put before first location
        #location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
        #    expires 14d;
        #    add_header Vary Accept-Encoding;
        #}

# For Naxsi remove the single # line for learn mode, or the ## lines for full WAF mode
        location / {
            #include    /nginx/conf/mysite.rules; # see also http block naxsi include line
            ##SecRulesEnabled;
         ##DeniedUrl "/RequestDenied";
         ##CheckRule "$SQL >= 8" BLOCK;
         ##CheckRule "$RFI >= 8" BLOCK;
         ##CheckRule "$TRAVERSAL >= 4" BLOCK;
         ##CheckRule "$XSS >= 8" BLOCK;
            root   html;
            index  index.html index.htm;
        }

# For Naxsi remove the ## lines for full WAF mode, redirect location block used by naxsi
        ##location /RequestDenied {
        ##    return 412;
        ##}

## Lua examples !
#         location /robots.txt {
#           rewrite_by_lua '
#             if ngx.var.http_host ~= "localhost" then
#               return ngx.exec("/robots_disallow.txt");
#             end
#           ';
#         }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000; # single backend process
        #    fastcgi_pass   myLoadBalancer; # or multiple, see example above
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }

    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

    # HTTPS server
    #
    #server {
    #    listen       443 ssl spdy;
    #    server_name  localhost;

    #    ssl                  on;
    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;
    #    ssl_session_timeout  5m;
    #    ssl_prefer_server_ciphers On;
    #    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    #    ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:ECDH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!eNULL:!MD5:!DSS:!EXP:!ADH:!LOW:!MEDIUM;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

3、cmd 到nginx根目录启动nginx

nginx.exe -c conf\nginx-win-rtmp.conf

测试:浏览器输入
http://localhost:5080/stat,看到

代表安装成功

4、下载ffmpeg安装

ffmpeg:一个处理音视频强大的库,我们需要用它来转协议,下载地址:
https://www.gyan.dev/ffmpeg/builds/ ,这里可以下载essential和full版本,essential就是简版,只包含ffmpeg.exe、ffplay.exe、

ffprobe.exe, 而full版本就包含了动态库和相关头文件,方便我们在开发中调用。

5、配置ffmpeg环境变量

将ffmpeg解压后里面的bin路径复制到Path里面去

6、测试ffmpeg

cmd ffmpeg -version 命令看到代表成功

7、下载VLC播放器

下载地址:
https://www.videolan.org/vlc/

8、查摄像头的rtsp协议格式

我这里截图是海康威视的

现在没有测试的流,我找了个点播的rtsp


rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4,用这个代替是一样的

9、执行ffmpeg命令

ffmpeg强大,命令也是复杂,我们cmd 执行

ffmpeg -re -rtsp_transport tcp -stimeout 20000000 -i "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4" -buffer_size 1024000 -max_delay 500000 -codec:v libx264 -r 25 -rtbufsize 10M -s 1280x720 -map:v 0 -an -f flv rtmp://127.0.0.1:1935/live/test


rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4,是输入源头


rtmp://127.0.0.1:1935/live/test 是输出地址

如果没有报错的话,到现在rtsp就已经转换好了

ffmpeg命令学习:
https://www.jianshu.com/p/df3216a52e59 、
https://blog.csdn.net/fuhanghang/article/details/123565920

10、测试rtmp是否转换成功

我们打开VLC,媒体->打开网络串流->输入
rtmp://127.0.0.1:1935/live/test
-> 播放

11、测试是否成功

等待几秒钟看到有视频播放就是成功了

12、为什么放弃了用rtmp

rtmp的优点是延迟低,效率高,但是在浏览器需要安装flash才能放,也就老版本的浏览器在用,rtmp可能会在别的地方支持,所以还是把他方式方法贴出来了。

三:方案二 rtsp转hls

1、nginx配置:

在前面已经贴出来了,其中这几个是针对hls的

2、执行ffmepg命令

ffmpeg -i "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4" -vcodec libx264 -acodec aac -f flv rtmp://127.0.0.1:1935/hls/test

3、查看nginx根目录 -> hls -> test.m3u8 是否生成

生成了代表一切正常

4、m3u8在网页上播放




    
    前端播放m3u8格式视频
    
    
    
    
    


    


source标签的src属性: http://你的nginx ip:nginx http端口/hls/test.m3u8

rtsp转HLS成功!

5、认识一下m3u8格式

m3u8文件里面存储了一个索引,以文本格式打开是这样的

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:56
#EXT-X-TARGETDURATION:13
#EXTINF:10.381,
test-56.ts
#EXTINF:10.422,
test-57.ts
#EXTINF:13.453,
test-58.ts

m3u8文件它不是视频源,源头是ts后缀文件

6、为什么放弃了用HLS

转HLS协议及网页加载过程:

ffmepg收到rtsp的流时候,会等一个切片的时间,一个切片时间到了,切片ts会放到服务器中,同时m3u8文件中加一个索引,对应着新进入的切片。网页在加载m3u8的时候,就是读取m3u8中的的索引去加载ts文件,所以在不断的请求ts,对ts进行解析,不断的和TCP握手,这就是为什么HLS延迟高和对网速的要求高的原因,我们监控肯定是要延迟低的,HLS兼容性好,适合点播。

四:方案三rtsp 转httpflv(采用)

1、安装nginx-flv-module

这个插件需要编译,教程:
https://blog.csdn.net/KayChanGEEK/article/details/105095844

我这里已经编译好了,直接下载启动:

https://gitee.com/isyuesen/nginx-flv-file

2、nginx配置

看我git里面的
https://gitee.com/isyuesen/nginx-flv-file/blob/master/conf/nginx.conf,和默认的config差别主要是添加了这几个

rtmp {  
    server {  
        listen 1935;
        # 流复用的最大块大小
        chunk_size 4000;  
        application liveapp { 
            live on;
            # 推流开始
			on_publish http://localhost:8081/auth;
			# 推流关闭
			on_publish_done http://localhost:8081/auth;
			# 客户端开始播放
			on_play http://localhost:8081/auth;
			# 客户端结束播放
			on_play_done http://localhost:8081/auth;
        }  
    }  
}
location /live {
    flv_live on;
    chunked_transfer_encoding on;
    add_header 'Access-Control-Allow-Credentials' 'true'; #add additional HTTP header
    add_header 'Access-Control-Allow-Origin' '*'; #add additional HTTP header
    add_header Access-Control-Allow-Headers X-Requested-With;
    add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
    add_header 'Cache-Control' 'no-cache';
}

3、做java权限认证

nginx rtmp配置中有配置on_publish钩子接口
http://localhost:8081/auth,这个回调HttpResponse stausCode如果不等于200会拒绝I/O,更多回调钩子看:
https://github.com/arut/nginx-rtmp-module/wiki/Directives#on_connect

@PostMapping("/auth")
    public void getVideo(String token, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        if (token.equals("tokenValue")) {
            httpServletResponse.setStatus(200);
        } else {
            // 拒绝服务
            httpServletResponse.setStatus(500);
        }
    }

4、执行ffmepg命令:

ffmpeg -re  -rtsp_transport tcp -i "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4" -f flv -vcodec h264 -vprofile baseline -acodec aac -ar 44100 -strict -2 -ac 1 -f flv -s 640*360 -q 10 "rtmp://127.0.0.1:1935/liveapp/test"

4.1 采用java代码去执行ffmepg命令

依赖 javaCV


    org.bytedeco
    javacv-platform
    1.5.2
public class App {
    public static void main( String[] args ) throws IOException, InterruptedException {
        String name = "test";
        // rtsp地址
        String rtspDir = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4";
        // rtmp地址
        String rtmpDir = "rtmp://192.168.0.140:1935/liveapp/" + name + "?token=tokenValue";

        String ffmpeg = Loader.load(org.bytedeco.ffmpeg.ffmpeg.class);
        ProcessBuilder pb = new ProcessBuilder(ffmpeg,
                "-re",
                "-rtsp_transport",
                "tcp",
                "-i",
                rtspDir,
                "-f",
                "flv",
                "-vcodec",
                "h264",
                "-vprofile",
                "baseline",
                "-acodec",
                "aac",
                "-ar",
                "44100",
                "-strict",
                "-2",
                "-ac",
                "1",
                "-f",
                "flv",
                "-s",
                "640*360",
                "-q",
                "10",
                rtmpDir
        );
        pb.inheritIO().start().waitFor();
    }
}

5、测试http-flv链接

如果你跟着我做的,那链接就是
http://127.0.0.1:18080/live?port=1935&app=liveapp&stream=test&token=tokenValue,在VLC播放器中点击媒体 -> 打开网络串流 -> 输入
http://127.0.0.1:18080/live?port=1935&app=liveapp&stream=test&token=tokenValue -> 播放

有视频证明你离成功就差最后一步

6、前端使用flv.js播放:




  
  
  
  播放http-flv






7、大功告成

相关推荐

JavaScript做个贪吃蛇小游戏(过关-加速),无需网络直接玩。

JavaScript做个贪吃蛇小游戏(过关-则加速)在浏览器打开文件,无需网络直接玩。<!DOCTYPEhtml><htmllang="en"><...

大模型部署加速方法简单总结(大模型 ai)

以下对大模型部署、压缩、加速的方法做一个简单总结,为后续需要备查。llama.cppGithub:https://github.com/ggerganov/llama.cppLLaMA.cpp项...

安徽医大第一医院应用VitaFlow Liberty(R)Flex为患者焕然一“心”

近日,在安徽医科大学第一附属医院心血管内科负责人暨北京安贞医院安徽医院业务副院长喻荣辉教授的鼎力支持和卓越带领下,凭借着先进的VitaFlowLiberty(R)Flex经导管主动脉瓣可回收可...

300 多行代码搞定微信 8.0 的「炸」「裂」特效!

微信8.0更新的一大特色就是支持动画表情,如果发送的消息只有一个内置的表情图标,这个表情会有一段简单的动画,一些特殊的表情还有全屏特效,例如烟花表情有全屏放烟花的特效,炸弹表情有爆炸动画并且消息和...

让div填充屏幕剩余高度的方法(div填充20px)

技术背景在前端开发中,经常会遇到需要让某个div元素填充屏幕剩余高度的需求,比如创建具有固定头部和底部,中间内容区域自适应填充剩余空间的布局。随着CSS技术的发展,有多种方法可以实现这一需求。实现步骤...

css之div内容居中(css中div怎么居中)

div中的内容居中显示,包括水平和垂直2个方向。<html><head><styletype="text/css">...

使用uniapp开发小程序遇到的一些问题及解决方法

1、swiper组件自定义知识点swiper组件的指示点默认是圆圈,想要自己设置指示点,需要获得当前索引,然后赋给当前索引不同的样式,然后在做个动画就可以了。*关键点用change方法,然后通过e.d...

微信小程序主页面排版(怎样设置小程序的排版)

开发小程序的话首先要了解里面的每个文件的作用小程序没有DOM对象,一切基于组件化小程序的四个重要的文件*.js*.wxml--->view结构---->html*.wxss--...

Vue动态组件的实践与原理探究(vue动态组件component原理)

我司有一个工作台搭建产品,允许通过拖拽小部件的方式来搭建一个工作台页面,平台内置了一些常用小部件,另外也允许自行开发小部件上传使用,本文会从实践的角度来介绍其实现原理。ps.本文项目使用VueCLI...

【HarmonyOS Next之旅】兼容JS的类Web开发(四) -> tabs

目录1->创建Tabs2->设置Tabs方向3->设置样式4->显示页签索引5->场景示例编辑1->创建Tabs在pages/index目录...

CSS:前端必会的flex布局,我把布局代码全部展示出来了

进入我的主页,查看更多CSS的分享!首先呢,先去看文档,了解flex是什么,这里不做赘述。当然,可以看下面的代码示例,辅助你理解。一、row将子元素在水平方向进行布局:1.垂直方向靠顶部,水平方向靠...

【HarmonyOS Next之旅】兼容JS的类Web开发(四) -> swiper

目录1->创建Swiper组件2->添加属性3->设置样式4->绑定事件5->场景示例编辑1->创建Swiper组件在pages/index...

CSS:Flex布局,网页排版神器!(css3 flex布局)

还在为网页排版抓狂?别担心,CSS的flex布局来了,让你轻松玩转各种页面布局,实现网页设计自由!什么是Flex布局?Flex布局,也称为弹性布局,是CSS中的一种强大布局方式,它能够让你...

移动WEB开发之flex布局,附携程网首页案例制作

一、flex布局体验传统布局兼容性好布局繁琐局限性,不能再移动端很好的布局1.1flex弹性布局:操作方便,布局极为简单,移动端应用很广泛PC端浏览器支持情况较差IE11或更低版本,不支持或仅部...

2024最新升级–前端内功修炼 5大主流布局系统进阶(mk分享)

2024最新升级–前端内功修炼5大主流布局系统进阶(mk分享)获课》789it.top/14658/前端布局是网页设计中至关重要的一环,它决定了网页的结构和元素的排列方式。随着前端技术的不断发展,现...