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格式一定要添加這個參數,否則丟幀會比較嚴重
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();
// 用來測試的frame窗口
final CanvasFrame cFrame = new CanvasFrame("frame");
Frame capturedFrame = null;
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、補充
(1)recorder的參數,有些需要根據設備和實際需求變化一下
(2)之前多次測試 recorder.setTimestamp(capturedFrame.timestamp); 這個地方的參數都使用了recorder.setTimestamp(grabber.getTimestamp()),但是執行一段時間之後就會報 -10054的錯誤,後來改成這個之後,比較穩定了
(3)爲了偷懶,這裏直接將異常拋出了,所以有時候程序出錯,也沒有退出,實際使用中需進行修改
(4)如果有什麼建議或者問題,可以給我留言