業務需求
最近公司在做養老相關的業務,現在需要子女從小程式端對家里的老人通過家庭終端互動屏進行實時看護,
解決方案
第三方的一些現成的服務:騰訊音視頻通話、直播功能; 阿里的音視頻通信;兩者都挺好的,但是需要收費因此放棄決定自己搭建一套直播流服務;
先看效果(自己服務器配置低有延遲、放到公司服務器上很流暢、清楚)

使用工具
Nginx、Nginx-Rtmp-Module
下載地址
Nginx:https://nginx.org/en/download.html
Nginx-Rtmp-Module:https://github.com/arut/nginx-rtmp-module
軟體安裝
1、下載Nginx
wget https://nginx.org/download/nginx-1.21.6.tar.gz
2、將壓縮包移到需要的安裝目錄下
mv nginx-1.21.6.tar.gz /usr/local
3、下載Nginx-Rtmp-Module
git clone https://github.com/arut/nginx-rtmp-module.git
4、將檔案移到需要安裝目錄下
mv nginx-rtmp-module /usr/local
5、進入目錄
cd /usr/local
6、解壓Nginx壓縮包
tar -zxvf nginx-1.21.6.tar.gz
7、進入Nginx目錄
cd nginx-1.21.6
8、配置
./configure --prefix=/usr/local/nginx --add-module=../nginx-rtmp-module --with-http_ssl_module
9、安裝
make && make install
10、配置 nginx.conf 檔案(/usr/local/nginx/conf下)
#user nobody;
# multiple workers works !
worker_processes 2;
#pid logs/nginx.pid;
events {
worker_connections 8192;
}
rtmp {
server {
listen 1935;
chunk_size 4000;
application live {
live on;
record all;
record_path /tmp/av;
record_max_size 1K;
record_unique on;
allow publish all;
deny publish all;
allow play all;
}
}
}
http {
include mime.types;
default_type application/octet-stream;
sendfile off;
server_names_hash_bucket_size 128;
client_body_timeout 10;
client_header_timeout 10;
keepalive_timeout 30;
send_timeout 10;
keepalive_requests 10;
#gzip on;
server {
listen 8080;
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 / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
11、啟動Nginx
cd /usr/local/nginx/sbin
./nginx -t
./nginx -s reload
啟動時可能會包錯:nginx: [error] invalid PID number "" in "/usr/local/nginx/logs/nginx.pid"
解決:
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
12、測驗(注意打開服務器8080和1935埠安全組)
訪問服務器外網 IP:8080

Java編碼實作直播推流、拉流
1、新建SpringBoot專案 pom.xml 引入所需的jar包
<!--直播相關依賴-->
<!--javacv-->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bytedeco.javacpp-presets/opencv-platform -->
<!--opencv-->
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>opencv-platform</artifactId>
<version>4.0.1-1.4.4</version>
</dependency>
2、新建直播推流實作類
package com.honyar.iot.vedio.pushandpullimpl;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;
import org.bytedeco.opencv.opencv_core.IplImage;
import javax.swing.*;
public class PushStream {
/**
* 直播推流實作
*/
public void getRecordPush(String outputPath, int v_rs) throws Exception, org.bytedeco.javacv.FrameRecorder.Exception, InterruptedException {
//創建采集器
OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0); //本地攝像頭默認為0
//開啟采集器
try {
grabber.start();
} catch (Exception e) {
try {
grabber.restart(); //一次重啟嘗試
} catch (Exception e2) {
throw e;
}
}
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage(); //轉換器
Frame grabframe = grabber.grab(); //獲取一幀
IplImage grabbedImage = null;
if (grabframe != null) {
grabbedImage = converter.convert(grabframe); //將這一幀轉換為IplImage
}
//創建錄制器
FrameRecorder recorder;
recorder = FrameRecorder.createDefault(outputPath, 1280, 720); //輸出路徑,畫面高,畫面寬
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); //設定編碼格式
recorder.setFormat("flv");
recorder.setFrameRate(v_rs);
recorder.setGopSize(v_rs);
//開啟錄制器
try {
recorder.start();
} catch (java.lang.Exception e) {
try {
if (recorder != null) { //嘗試重啟錄制器
recorder.stop();
recorder.start();
}
} catch (java.lang.Exception e1) {
e.printStackTrace();
}
}
//直播效果展示視窗
CanvasFrame frame = new CanvasFrame("主播-菜雞-德華", CanvasFrame.getDefaultGamma() / grabber.getGamma());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setAlwaysOnTop(true);
//推流
while (frame.isVisible() && (grabframe = grabber.grab()) != null) {
frame.showImage(grabframe); //展示直播效果
grabbedImage = converter.convert(grabframe);
Frame rotatedFrame = converter.convert(grabbedImage);
if (rotatedFrame != null) {
recorder.record(rotatedFrame);
}
Thread.sleep(50); //50毫秒/幀
}
}
}
3、新建直播推流啟動類
package com.honyar.iot.vedio.start;
import com.honyar.iot.vedio.pushandpullimpl.PushStream;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
/**
* 直播推流--啟動
*/
@SpringBootApplication
@Configuration
public class PushApplication {
public static void main(String[] args) throws Exception {
//設定rtmp服務器推流地址(寫你自己服務器外網地址)
String outputPath = "rtmp://xxx.xx.xxx.xx:1935/live/address";
PushStream recordPush = new PushStream();
recordPush.getRecordPush(outputPath, 25);
}
}
4、新建直播拉流實作類
package com.honyar.iot.vedio.pushandpullimpl;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.*;
import org.bytedeco.opencv.opencv_core.IplImage;
import javax.swing.*;
public class PushStream {
/**
* 直播推流實作
*/
public void getRecordPush(String outputPath, int v_rs) throws Exception, org.bytedeco.javacv.FrameRecorder.Exception, InterruptedException {
//創建采集器
OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0); //本地攝像頭默認為0
//開啟采集器
try {
grabber.start();
} catch (Exception e) {
try {
grabber.restart(); //一次重啟嘗試
} catch (Exception e2) {
throw e;
}
}
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage(); //轉換器
Frame grabframe = grabber.grab(); //獲取一幀
IplImage grabbedImage = null;
if (grabframe != null) {
grabbedImage = converter.convert(grabframe); //將這一幀轉換為IplImage
}
//創建錄制器
FrameRecorder recorder;
recorder = FrameRecorder.createDefault(outputPath, 1280, 720); //輸出路徑,畫面高,畫面寬
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); //設定編碼格式
recorder.setFormat("flv");
recorder.setFrameRate(v_rs);
recorder.setGopSize(v_rs);
//開啟錄制器
try {
recorder.start();
} catch (java.lang.Exception e) {
try {
if (recorder != null) { //嘗試重啟錄制器
recorder.stop();
recorder.start();
}
} catch (java.lang.Exception e1) {
e.printStackTrace();
}
}
//直播效果展示視窗
CanvasFrame frame = new CanvasFrame("主播-菜雞-德華", CanvasFrame.getDefaultGamma() / grabber.getGamma());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setAlwaysOnTop(true);
//推流
while (frame.isVisible() && (grabframe = grabber.grab()) != null) {
frame.showImage(grabframe); //展示直播效果
grabbedImage = converter.convert(grabframe);
Frame rotatedFrame = converter.convert(grabbedImage);
if (rotatedFrame != null) {
recorder.record(rotatedFrame);
}
Thread.sleep(50); //50毫秒/幀
}
}
}
5、新建直播拉流啟動類(可以多建幾個模擬多個客戶端)
package com.honyar.iot.vedio.start;
import com.honyar.iot.vedio.pushandpullimpl.PullStream;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
/**
* 直播拉流--啟動
*/
@SpringBootApplication
@Configuration
public class PullApplication1 {
public static void main(String[] args) throws Exception {
//rtmp服務器拉流地址(自己服務器外網地址)
String inputPath = "rtmp://xxx.xx.xxx.xx/live/address";
PullStream pullStream = new PullStream();
pullStream.getPullStream(inputPath);
}
}
6、測驗

輸了不可怕,大不了從頭再來,我們還年輕---周紅
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/465985.html
標籤:其他
上一篇:Java中 String s = new String("java265.com")創建了幾個物件呢
下一篇:final關鍵字簡介說明
