1、测试的目标
将海康威视摄像头产生的rtsp视频流,通过java代码转换后,以rtmp的形式推送到nginx服务器,实现远程访问。推流程序需要和设备在同一个局域网下(否则获取不到视频流),nginx可以在本地服务器,也可以是云服务器。
2、工具和环境
eclipse、maven、jdk1.8、javacv-1.5.1、nginx1.17.1、VLC media player、iVMS-4200客户端
3、相关说明
(1)不同版本的javacv的包,有些类的位置有不同,下面是我用的包的maven地址
org.bytedeco
javacv-platform
1.5.1
(2)iVMS-4200客户端是用来设置摄像头IP的,设备的账号密码等信息,由设备厂家提供,摄像头的rtsp地址:
rtsp://{username}:{password}@{ip}/h264/1/main/av_stream
(3)nginx在window上部署可以直接下载到包含rtmp的包,linux上需要下载插件包自行编译,需要的可以给我留言
(4)VLC media player是用来预览rtmp视频流的,也可以用web页面访问,参考代码(ezuikit.js官方demo中有):
4、Java代码
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
public class TestClass {
public static void main(String[] args) throws Exception{
final int captureWidth = 1280;
final int captureHeight = 720;
final FFmpegFrameGrabber grabber = new FFmpegFrameGrabber("{rtspUrl}");
grabber.setImageWidth(captureWidth);
grabber.setImageHeight(captureHeight);
// rtsp格式一般添加TCP配置,否则丢帧会比较严重
// Brick在测试过程发现,该参数改成udp可以解决部分电脑出现的下列报警,但是丢帧比较严重
// av_interleaved_write_frame() error -22 while writing interleaved video packet.
grabber.setOption("rtsp_transport", "tcp");
grabber.start();
// 最后一个参数是AudioChannels,建议通过grabber获取
final FFmpegFrameRecorder recorder = new FFmpegFrameRecorder("{rtmpUrl}", captureWidth, captureHeight, 1);
recorder.setInterleaved(true);
// 降低编码延时
recorder.setVideoOption("tune", "zerolatency");
// 提升编码速度
recorder.setVideoOption("preset", "ultrafast");
// 视频质量参数(详见 https://trac.ffmpeg.org/wiki/Encode/H.264)
recorder.setVideoOption("crf", "28");
// 分辨率
recorder.setVideoBitrate(2000000);
// 视频编码格式
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
// 视频格式
recorder.setFormat("flv");
// 视频帧率
recorder.setFrameRate(15);
recorder.setGopSize(60);
recorder.setAudioOption("crf", "0");
recorder.setAudioQuality(0);
recorder.setAudioBitrate(192000);
recorder.setSampleRate(44100);
// 建议从grabber获取AudioChannels
recorder.setAudioChannels(1);
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
recorder.start();
// 解决音视频同步导致的延时问题
Field field = recorder.getClass().getDeclaredField("oc");
field.setAccessible(true);
AVFormatContext oc = (AVFormatContext)field.get(recorder);
oc.max_interleave_delta(100);
// 用来测试的frame窗口
final CanvasFrame cFrame = new CanvasFrame("frame");
Frame capturedFrame = null;
// 有些时候,程序执行回报下列错误,添加一行代码解决此问题
// av_interleaved_write_frame() error -22 while writing interleaved video packet.
grabber.flush();
while ((capturedFrame = grabber.grab()) != null) {
if (cFrame.isVisible()){
cFrame.showImage(capturedFrame);
}
System.out.println(grabber.getFrameNumber()+ "--" +capturedFrame.timestamp);
recorder.setTimestamp(capturedFrame.timestamp);
recorder.record(capturedFrame);
}
cFrame.dispose();
recorder.close();
grabber.close();
}
}
5、rtsp视频流地址(地址正确可以在vlc中播放)
rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream
username: 用户名;password: 密码;ip: 设备IP;port:设备端口,默认554时可略; codec:h264等;channel: 通道号;
subtype: 码流类型,主码流为main,辅码流为sub
例(DS-IPC-E22H-1W型) rtsp://admin:[email protected]/h264/1/main/av_stream
补充:地址也可以是rtsp://[username]:[password]@[ip]:[port]/live.sdp
例(DS-IPC-E22H-1W型) rtsp://admin:[email protected]/live.sdp
6、rtmp视频流地址(地址正确可以在vlc中播放)
rtmp://[ip]:[port]/[rtmp-addr]/[camera-name]
ip: nginx服务器IP;port:nginx的rtmp端口;rtmp-addr:配置的rtmp地址;camera-name:推流摄像头地址名称
例 rtmp://192.168.100.10:1935/hls/test01
7、附上测试时候用的nginx的配置文件
worker_processes 1;
error_log logs/error.log notice;
events {
worker_connections 1024;
}
rtmp {
server {
listen 8012;
application myapp {
live on;
}
application hls {
live on;
hls on;
hls_path /usr/local/nginx/temp/hls;
hls_fragment 1s;
hls_playlist_length 3s;
}
}
}
http {
server {
listen 8011;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
alias /usr/local/nginx/temp/hls;
expires -1;
}
}
}
8、补充
(1)recorder的参数,有些需要根据设备和实际需求变化一下
(2)使用recorder.setTimestamp(grabber.getTimestamp())执行一段时间之后就会报 -10054的错误
(3)实际使用中要关闭grabber和recorder,先使用release,再使用close,否则会导致服务停止
(4)最终测试结果:使用vlc播放有5-8s延时,使用web播放延时仅为1s左右
(5)如果有什么建议或者问题,可以给我留言(微信yl4757)