其實(shí)原理就是: 將監(jiān)控通過FFMPEG,推送給Nginx,前端通過Nginx地址拉取視頻,就可以播放了。
1:安裝FFMPEG.
2:下載并且配置nginx.
3:使用java代碼實(shí)現(xiàn)調(diào)用cmd或者linux窗口,并且運(yùn)行操作FFMPEG的命令,進(jìn)行監(jiān)控視頻rtsp格式的推送,推送給nginx.
4:前端寫一個(gè)video標(biāo)簽就可以,Src寫nginx的固定地址就可以。
windows: url: 【在上面3:中提到的,通過ffmeg推送給nginx的命令如下】
ffmpeg -rtsp_transport tcp -i 你的rtsp地址 -c:v libx264 -c:a aac -f flv -an rtmp://你的nginx地址:nginx配置的拉取端口號/myapp/room
linux:url:
ffmpeg -f rtsp -rtsp_transport tcp -i ' 你的rtsp地址監(jiān)控視頻' -codec copy -f flv -an 'rtmp://你的nginx地址:nginx配置的拉取端口號/myapp/room'
環(huán)境
- 本地系統(tǒng) win10
- centos7:Nginx
- 開源程序:ffmpeg
- 前端:Vue
- 后端SpringBoot
一、下載所需要的FFMPEG安裝包
- windows下載FFmpeg FFMpeg windows版本
-https://www.gyan.dev/ffmpeg/builds/
將此文件解壓到你喜歡的的文件夾【比如這樣】
接著配置環(huán)境變量
進(jìn)入到解壓后的目錄找到bin 、復(fù)制bin目錄路徑----然后配置系統(tǒng)環(huán)境變量【下圖所示】
cmd查看一下是否成功
ffmpeg
至此這個(gè)這個(gè)玩意就安裝完成了
安裝nginx
依照你喜歡的方式安裝nginx 可以使用docker、yum、安裝包 等等方式都可以
我使用直接解壓的方式
可以去nginx官網(wǎng)下載喜歡的nginx版本 ,上傳到服務(wù)器
解壓然后編譯(這個(gè)應(yīng)該不難,可以使用 make make install )
安裝完成之后長這樣
可以看到我這個(gè)截圖上多了一個(gè) nginx-http-flv-module 這個(gè)目錄,這個(gè)是必要安裝的一個(gè)模塊
否則無法實(shí)現(xiàn)正常的監(jiān)控視頻播放
給Nginx安裝 nginx-http-flv-module模塊
建議直接下載到nginx的目錄下、我安裝到了 /user/loacl/nginx/ 文件夾下了
下載地址:https://github.com/winshining/nginx-http-flv-module
安裝依賴項(xiàng)
yum -y install unzip
yum -y install gcc-c++
yum -y install pcre pcre-devel
yum -y install zlib zlib-devel
yum -y install openssl openssl-devel
將nginx-http-flv-module模板添加到nginx中,生成make文件 并安裝nginx
./configure --prefix=/usr/local/nginx --add-module=/usr/local/nginx/nginx-http-flv-module
make && make install
檢查是否安裝成功
nginx -V
出現(xiàn)這個(gè)就是代表安裝成功了
安裝基本已經(jīng)成形---------接下來配置nginx的配置文件
nginx配置文件
## 編輯nginx配置文件
vim conf/nginx.conf
nginx的配置文件大概就是這樣的(完成的nginx配置文件 我也會(huì)在下面附上,可以直接復(fù)制* 嗷對 需要修改成你的ip 或者域名)
下面是完整的ngin配置文件
worker_processes 10; #should be 1 for Windows, for it doesn't support Unix domain socket
#worker_processes auto; #from versions 1.3.8 and 1.2.5
#worker_cpu_affinity 0001 0010 0100 1000; #only available on FreeBSD and Linux
#worker_cpu_affinity auto; #from version 1.9.10
error_log logs/error.log error;
#if the module is compiled as a dynamic module and features relevant
#to RTMP are needed, the command below MUST be specified and MUST be
#located before events directive, otherwise the module won't be loaded
#or will be loaded unsuccessfully when NGINX is started
#load_module modules/ngx_http_flv_live_module.so;
events {
worker_connections 10240;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 9000; #http-flv的拉流端口
server_name 【這個(gè)地方寫你的ip、或者說是域名都是可以的--】; #http-flv的拉流ip
location / {
root html;
index index.html index.htm;
}
#http-flv的相關(guān)配置
location /live{
flv_live on; #打開HTTP播放FLV直播流功能
chunked_transfer_encoding on;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
}
location /hls{
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /usr/local/nginx/html/hls;
add_header 'Cache-Control' 'no-cache';
}
location /dash {
root /usr/local/nginx/html/dash;
add_header 'Cache-Control' 'no-cache';
}
location /stat {
#configuration of push & pull status
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl {
root /usr/local/nginx/nginx-http-flv-module;
}
location /control {
rtmp_control all; #configuration of control module of rtmp
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
rtmp_auto_push on;
rtmp_auto_push_reconnect 1s;
rtmp_socket_dir /tmp;
rtmp{
out_queue 4096;
out_cork 8;
max_streams 128;
timeout 15s;
drop_idle_publisher 15s;
log_interval 5s;
log_size 1m;
server{
#推流端口
listen 1935;
#推流應(yīng)用名稱
application myapp{
live on;
record off;
gop_cache on;
}
application hls{
live on;
hls on;
hls_path /usr/local/nginx/html/hls;
hls_fragment 1s;
hls_playlist_length 3s;
}
application dash{
live on;
dash on;
dash_path /usr/local/nginx/html/dash;
}
}
}
測試一下是否可以使用:準(zhǔn)備一個(gè)可播放的rtsp地址例如:???、大華、。。。。。都可以試試
打開cmd 開始調(diào)用 ffmpeg
ffmpeg -rtsp_transport tcp -i rtsp://user:pwd@ip:31554/h264/ch1/main/av_stream -c:v libx264 -c:a aac -f flv -an rtmp://nginx的ip:nginx所配的端口/myapp/room
如果出現(xiàn)如下,有速度就代表可以成功
可以使用地址本地測試一下有沒有畫面
'http://nginx的ip:nginx訪問的端口9000/live?port=1935&app=myapp&stream=room'
打開VLC media player
前端 (vue)
引入Flv.js
然后接下來就這么寫【如下圖】會(huì)附上全代碼
<template>
<a-modal
:title="title"
:width="510"
:visible="visible"
switchFullscreen
@ok="handleOk"
@cancel="handleCancel"
cancelText="關(guān)閉"
>
<a-spin :spinning="confirmLoading">
<j-form-container>
<a-form :form="form" slot="detail">
<a-row>
<video autoplay controls width="100%" height="270" id="videoElement"></video>
</a-row>
</a-form>
</j-form-container>
</a-spin>
</a-modal>
</template>
<script>
import flvjs from 'flv.js'
import JFormContainer from '@/components/jeecg/JFormContainer'
import { getAction } from '../../../api/manage'
export default {
name: 'VidoModule',
components: {
JFormContainer,
flvjs,
},
data() {
return {
flvPlayer:1,
title: '監(jiān)控',
//源視頻地址
videoPath:'',
videoStream: '',
confirmLoading: false,
visible: false,
form: this.$form.createForm(this),
url: {
//開啟視頻
list: '自己的請求地址',
//關(guān)閉視頻輸出
list1:'。。。'
},
}
},
mounted() {
},
methods: {
// 開啟頁面
show(record) {
this.visible = true
this.videoPath = record.videoPath
this.VideoData(this.videoPath);
this.createVideo()
},
VideoData(videoPath){
getAction(this.url.list,{videoPath:videoPath}).then((res) => {
})
},
//傳輸視頻地址
createVideo() {
if (flvjs.isSupported()) {
let videoElement = document.getElementById('videoElement')
let flvPlayer = flvjs.createPlayer({
type: 'flv',
isLive: true,
fluid: true,
stashInitialSize: 128,// 減少首楨顯示等待時(shí)長
url: 'http://xxx.xxx.xxx.xxx:9000/live?port=1935&app=myapp&stream=room', //url地址
})
//console.log(videoUrl+' videoUrl')
flvPlayer.attachMediaElement(videoElement)
flvPlayer.load()
flvPlayer.play()
}
},
close() {
this.$emit('close')
this.visible = false
this.closeFfmpeg()
},
// 關(guān)閉視頻的輸出
closeFfmpeg(){
getAction(this.url.list1).then((res) => {
})
},
handleOk() {
this.submitForm()
},
submitCallback() {
this.$emit('ok')
this.visible = false
},
handleCancel() {
this.close()
},
},
}
</script>
<style lang="less" scoped>
</style>
后端 SpringBoot
后端其實(shí)就是通過java 去調(diào)用本地或者服務(wù)器上的FFMPEG,使用cmd 或者 shell的方式都可以
其實(shí)就是執(zhí)行一下命令而已
CommandUtil.java
package common.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @Description: 調(diào)用命令 【windows&Linux】 @Author: cq @Date: 2022/12/20 @Version: V1.0
* 用于啟動(dòng)ffmpeg 隨之將rtsp 轉(zhuǎn)化為rtmp 返回給Flv.js使用
*/
public class CommandUtil {
/** 調(diào)用linux命令* */
public String linuxExec(String cmd) {
System.out.println("執(zhí)行命令[ " + cmd + "]");
Runtime run = Runtime.getRuntime();
try {
Process process = run.exec(cmd);
String line;
BufferedReader stdoutReader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuffer out = new StringBuffer();
while ((line = stdoutReader.readLine()) != null) {
out.append(line);
}
try {
process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
process.destroy();
return out.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/** 調(diào)用windwos命令* */
public String winExec(String cmd) {
Runtime runtime = Runtime.getRuntime();
String command =cmd;
try {
Process process = runtime.exec(command);
new InputStreamReader(process.getInputStream());
return "成功";
} catch (IOException e) {
e.printStackTrace();
return "請檢查攝像頭地址";
}
}
}
package org.ept.modules.solidwaste.controller;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ept.common.api.vo.Result;
import org.ept.common.util.CommandUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* @Description: 視頻輸出 @Author: cq @Date: 2022/11/30 @Version: V1.0
*/
@Api(tags = "視頻格式轉(zhuǎn)換---windows-->cmd---linux")
@RestController
@RequestMapping("/video/videos")
@AllArgsConstructor
@Slf4j
public class videoTestController {
/** Windows系統(tǒng)* */
private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("win");
/** Linux系統(tǒng)* */
private static final boolean IS_LINUX = System.getProperty("os.name").toLowerCase().contains("Linux");
/** 視頻播放指令執(zhí)行 rtsp地址【源播放地址】通過ffmpeg程序進(jìn)行轉(zhuǎn)化成rtmp,將地址傳給flv.js進(jìn)行播放 */
@GetMapping("/videoStart")
public void videoPreview(@RequestParam(name = "videoPath", required = false) String videoPath) {
CommandUtil commandUtil = new CommandUtil();
/*如果是winodws系統(tǒng)**/
if (IS_WINDOWS) {
String cmd ="cmd /k start ffmpeg -rtsp_transport tcp -i"
+ " "
+ videoPath
+ " "
+ "-c:v libx264 -c:a aac -f flv -an rtmp://xxx.xxx.xxx.xxx:1935/myapp/room";
commandUtil.winExec(cmd);
}
/*如果是Linux系統(tǒng)**/
if (IS_LINUX){
System.out.println("linux");
String cmd = "ffmpeg -f rtsp -rtsp_transport tcp -i '"
+ ""
+ videoPath
+ "'"
+ ""
+ " -codec copy -f flv -an 'rtmp://xxx.xxx.xxx.xxx:1935/myapp/room'";
commandUtil.linuxExec(cmd);
}
}
/** 關(guān)閉ffmpeg.exe程序 */
@GetMapping("/videoClose")
public Result<?> close() {
closeHistoryProgram("ffmpeg.exe");
return Result.ok("已成功停止");
}
public void closeHistoryProgram(String processName) {
String cmd = "taskkill /f /t /im " + processName;
try {
// exec執(zhí)行cmd命令
Process process = Runtime.getRuntime().exec(cmd);
// 獲取CMD命令結(jié)果的輸出流
InputStream fis = process.getInputStream();
InputStreamReader isr = new InputStreamReader(fis, "GBK");
// 使用緩沖器讀取
BufferedReader br = new BufferedReader(isr);
String line = null;
// 全部讀取完成為止,一行一行讀取
while ((line = br.readLine()) != null) {
// 輸出讀取的內(nèi)容
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
大概就是這么個(gè)意思文章來源:http://www.zghlxwxcb.cn/news/detail-414953.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-414953.html
到了這里,關(guān)于SpringBoot+vue 實(shí)現(xiàn)監(jiān)控視頻rtsp播放(java+Nginx+ffmpeg+flv.js)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!