目录
一:理解音视频流协议:二:方案一 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 转rtmp1、下载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] 34;$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转hls1、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在网页上播放
<!DOCTYPE html><html lang="zh-CN"><head> <meta charset="UTF-8"> <title>前端播放m3u8格式视频</title> <!--https://www.bootcdn.cn/video.js/--> <link href="https://cdn.bootcss.com/video.js/7.6.5/alt/video-js-cdn.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/video.js/6.6.2/video.js"></script> <!--https://www.bootcdn.cn/videojs-contrib-hls/--> <script src="https://cdn.bootcss.com/videojs-contrib-hls/5.15.0/videojs-contrib-hls.min.js"></script></head><body> <video id="myVideo" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto" width="1080" height="708" data-setup='{}'> <source id="source" src="http://127.0.0.1:5080/hls/test.m3u8" type="application/x-mpegURL"> </video></body><script> // videojs 大略利用 var myVideo = videojs('myVideo',{ bigPlayButton : true, textTrackDisplay : false, posterImage: false, errorDisplay : false, }) myVideo.play() // 视频播放 myVideo.pause() // 视频停息</script></html>
source标签的src属性: http://你的nginx ip:nginx http端口/hls/test.m3u8
rtsp转HLS成功!
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 640360 -q 10 "rtmp://127.0.0.1:1935/liveapp/test"
4.1 采取java代码去实行ffmepg命令
依赖 javaCV
<dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv-platform</artifactId> <version>1.5.2</version></dependency>
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", "640360", "-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播放:<!doctype html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>播放http-flv</title></head><body><video id="videoElement"></video><script src="https://cdn.bootcdn.net/ajax/libs/flv.js/1.6.2/flv.min.js"></script><script> if (flvjs.isSupported()) { const videoElement = document.getElementById('videoElement'); const flvPlayer = flvjs.createPlayer({ type: 'flv', url: 'http://127.0.0.1:18080/live?port=1935&app=liveapp&stream=test&token=tokenValue' }); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); flvPlayer.play();}</script></body></html>
7、大功告成