首页 技术 正文
技术 2022年11月13日
0 收藏 805 点赞 2,993 浏览 6472 个字

业务需求

最近公司在做养老相关的业务,现在需要子女从小程序端对家里的老人通过家庭终端交互屏进行实时看护。

解决方案

第三方的一些现成的服务:腾讯音视频通话、直播功能; 阿里的音视频通信;两者都挺好的,但是需要收费因此放弃决定自己搭建一套直播流服务;

先看效果(自己服务器配置低有延迟、放到公司服务器上很流畅、清楚)

使用工具

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、测试

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,996
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,510
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,353
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,137
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,770
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,848