海康威视rtsp转rtmp(java稳定版)

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地址

<dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv-platform</artifactId>
    <version>1.5.1</version>
</dependency>

(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中有):

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
	<meta charset="UTF-8">
</head>
<script src="jquery-1.11.3.min.js"></script>
<script src="ezuikit.js"></script>
<script>
$(function () {
	var player08 = new EZUIPlayer('myPlayer08');
	player08.play();
})
</script>

<body>
	<div style="border:1px solid red">
		<div>
		  <video id="myPlayer08" controls playsInline webkit-playsinline width="800" height="600">
		    <source src="rtmp://{ip}:{port}/{name}" type="rtmp/flv" />
		  </video>
		</div>
	</div>
</body>

<style>
div{
	display:inline-block;
	padding:0;
	margin:0;
}
</style>
</html>

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.

		int oldFrameNumber = Integer.MIN_VALUE;
		long oldTimestamp = Long.MIN_VALUE;

		while ((capturedFrame = grabber.grab()) != null) {
			if (cFrame.isVisible()) {
				cFrame.showImage(capturedFrame);
			}
			int newFrameNumber = grabber.getFrameNumber();
			long newTimestamp = capturedFrame.timestamp;
			if (newFrameNumber < oldFrameNumber) {
				continue;
			} else if (newFrameNumber > oldFrameNumber) {
				oldTimestamp = Long.MIN_VALUE;
			}
			if (newTimestamp < oldTimestamp) {
				continue;
			}
			oldFrameNumber = newFrameNumber;
			oldTimestamp = newTimestamp;
			System.out.println(newFrameNumber + "--" + newTimestamp);
			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:HikQTXVLV@192.168.0.100/h264/1/main/av_stream

    补充:地址也可以是rtsp://[username]:[password]@[ip]:[port]/live.sdp

    例(DS-IPC-E22H-1W型) rtsp://admin:HikQTXVLV@192.168.0.100/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的配置文件

(1) 考虑hls(延时会比较高,但是可以不依赖flash)

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;
		}
	}
}


(2) 不用hls(延时会比较第,但是需要依赖flash)

worker_processes  1;

error_log  logs/error.log  notice;

events {
    worker_connections  1024;
}

rtmp {  
    server {
        listen 8012;
        application hls {  
            live on;  
       }  
    } 
}

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;
        }
	}
}

8、补充

(1)recorder的参数,有些需要根据设备和实际需求变化一下

(2)使用recorder.setTimestamp(grabber.getTimestamp())执行一段时间之后就会报 -10054的错误

(3)实际使用中要关闭grabber和recorder,先使用release,再使用close,否则会导致服务停止

(4)最终测试结果:使用vlc播放有5-8s延时,使用web播放延时仅为1s左右

  • 12
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 62
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 62
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值