1.實(shí)時視頻流解決方案
目錄
1.實(shí)時視頻流解決方案
2.步驟
1.搭建rtmp+flv服務(wù)器
2.java預(yù)覽demo
3.實(shí)時預(yù)覽
1.配置??祍dk庫文件
2.修改FPREVIEW_NEWLINK_CB代碼,推流
3.修改FPREVIEW_DATA_CB代碼,取流
4.javacv的推流
3.部分代碼
1.啟動項(xiàng)目初始化cms,stream的代碼
2.cms代碼
3.stream代碼
1.前端調(diào)用后臺接口,
2.后臺接口調(diào)用??祍dk開啟具體的攝像頭監(jiān)聽,獲取攝像頭實(shí)時流數(shù)據(jù)
3.建立管道,海康sdk監(jiān)聽線程和javacv推流線程共享管道
4.sdk線程向管道輸出流寫數(shù)據(jù),javacv推流線程向rtmp發(fā)送管道數(shù)據(jù)。即sdk生產(chǎn)者,javacv是消費(fèi)者
5.nginx+rtmp+flv模塊接收到視頻流,可以通過http的路徑在瀏覽器訪問
前端->后臺->海康sdk—>管道->javacv->nginx+rtmp+flv->http路徑
2.步驟
1.搭建rtmp+flv服務(wù)器
windows系統(tǒng)下,自己編譯比較麻煩,這邊有大佬編譯好的windows中obs+nginx-http-flv-module的流媒體服務(wù)搭建_windows nginx集成http-flv_OneCodeSolvesAll的博客-CSDN博客個人編譯好的:鏈接:https://pan.baidu.com/s/1XKkyYvK5W6yZA1w2mPaAfg
提取碼:3ug6
linux環(huán)境下,下載nginx-http-flv-module(包含nginx-rtmp-module),添加到nginx重載配置就行,網(wǎng)上有很多教程。
如果不需要flv,也可以單獨(dú)下載nginx-rtmp-module,添加到nginx重載配置。
2.java預(yù)覽demo
1.登錄海康平臺??甸_放平臺
選擇硬件產(chǎn)品的isup sdk下載
2.解壓之后
?java的這個demo直接打開,修改一下nvr信息,包括ip端口就可以直接預(yù)覽。
3.實(shí)時預(yù)覽
1.配置??祍dk庫文件
??滴臋nlib文件夾下的文件就是庫文件,JavaISUPDemo\lib下也有,需要注意文檔是win還是linux版本的。
2.修改FPREVIEW_NEWLINK_CB代碼,推流
每當(dāng)NET_ECMS_StartGetRealStreamV11,開啟預(yù)覽時,F(xiàn)PREVIEW_NEWLINK_CB便會監(jiān)聽到預(yù)覽請求。
創(chuàng)建管道,分別用于取流推流。異步開始調(diào)用javacv的推流方法。
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream();
Stream.streamMap.put("stream:"+lLinkHandle,pos);
pos.connect(pis);
CompletableFuture.runAsync(()-> {
try {
PushUtil.grabAndPushRtmp(pis,"rtmp://"+rtmphost+"/live/"+userId+"_"+ dwChannelNo);
} catch (Exception e) {
e.printStackTrace();
}
}, Executors.newFixedThreadPool(1));
3.修改FPREVIEW_DATA_CB代碼,取流
每當(dāng)監(jiān)聽到視頻流時,將視頻流寫入pos管道。注意此處不能使用redis,redis會嚴(yán)重影響此處代碼性能,導(dǎo)致取流失敗。每監(jiān)聽一次,是一個新的線程。第一塊注釋的代碼是調(diào)試時使用,調(diào)試完之后要刪掉。第二塊注釋代碼pos也可以存到map中,使用時從map取,此處直接構(gòu)造方法傳進(jìn)來也可以。
public class FPREVIEW_DATA_CB implements HCISUPStream.PREVIEW_DATA_CB {
private PipedOutputStream pos;
public FPREVIEW_DATA_CB(PipedOutputStream pos) {
this.pos = pos;
}
//實(shí)時流回調(diào)函數(shù)/
@Override
public void invoke(int iPreviewHandle, HCISUPStream.NET_EHOME_PREVIEW_CB_MSG pPreviewCBMsg, Pointer pUserData) throws Exception {
// if (Count == 500) {//降低打印頻率
// log.info("FPREVIEW_DATA_CB callback, iPreviewHandle:{}", iPreviewHandle);
// log.info("FPREVIEW_DATA_CB callback, data length:" + pPreviewCBMsg.dwDataLen);
// Count = 0;
// }
// Count++;
long offset = 0;
ByteBuffer buffers = pPreviewCBMsg.pRecvdata.getByteBuffer(offset, pPreviewCBMsg.dwDataLen);
byte[] bytes = new byte[pPreviewCBMsg.dwDataLen];
buffers.rewind();
buffers.get(bytes);
try{
//2.將數(shù)據(jù)讀入到內(nèi)存空間,此處不可用redis,否則執(zhí)行時間是當(dāng)前10倍
// PipedOutputStream pos = Stream.streamMap.get("stream:"+iPreviewHandle);
pos.write(bytes);
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.javacv的推流
關(guān)于2.提到的javacv推流,linux和windows環(huán)境所需要的依賴包不同。
以下,test的是本地windows環(huán)境使用的,runtime是線上使用的,可不寫,因?yàn)槟J(rèn)就是runtime。
<!-- Linux x86_64 使用 --> <dependency> <groupId>org.bytedeco</groupId> <artifactId>javacpp</artifactId> <version>1.5.7</version> </dependency> <dependency> <groupId>org.bytedeco</groupId> <artifactId>opencv</artifactId> <version>4.5.5-1.5.7</version> <classifier>linux-x86_64</classifier> <scope>runtime</scope> </dependency> <dependency> <groupId>org.bytedeco</groupId> <artifactId>openblas</artifactId> <version>0.3.19-1.5.7</version> <classifier>linux-x86_64</classifier> <scope>runtime</scope> </dependency> <dependency> <groupId>org.bytedeco</groupId> <artifactId>ffmpeg</artifactId> <version>5.0-1.5.7</version> <classifier>linux-x86_64</classifier> <scope>runtime</scope> </dependency> <!-- Windows x86_64 使用 --> <dependency> <groupId>org.bytedeco</groupId> <artifactId>opencv</artifactId> <version>4.5.5-1.5.7</version> <classifier>windows-x86_64</classifier> <scope>test</scope> </dependency> <dependency> <groupId>org.bytedeco</groupId> <artifactId>openblas</artifactId> <version>0.3.19-1.5.7</version> <classifier>windows-x86_64</classifier> <scope>test</scope> </dependency> <dependency> <groupId>org.bytedeco</groupId> <artifactId>ffmpeg</artifactId> <version>5.0-1.5.7</version> <classifier>windows-x86_64</classifier> <scope>test</scope> </dependency> <dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv</artifactId> <version>1.5.7</version> <exclusions> <exclusion> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency>
推流代碼原理就是,javacv抓取幀,根據(jù)幀率算出間隔時間推送到rtmp服務(wù)器。
package com.ei.ambulance.util.video;
import org.bytedeco.ffmpeg.avcodec.AVCodecParameters;
import org.bytedeco.ffmpeg.avformat.AVFormatContext;
import org.bytedeco.ffmpeg.avformat.AVStream;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.FFmpegLogCallback;
import org.bytedeco.javacv.Frame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.PipedInputStream;
/**
* @author willzhao
* @version 1.0
* @description 讀取指定的mp4文件,推送到SRS服務(wù)器
* @date 2021/11/19 8:49
*/
public class PushUtil {
private static final Logger log = LoggerFactory.getLogger(PushUtil.class);
/**
* 推送到SRS服務(wù)器
*
* @param pis
* @param pushAddress 推流地址
* @throws Exception
*/
public static void grabAndPushRtmp(PipedInputStream pis, String pushAddress) throws Exception {
Thread.sleep(500);
// ffmepg日志級別
avutil.av_log_set_level(avutil.AV_LOG_ERROR);
FFmpegLogCallback.set();
// 實(shí)例化幀抓取器對象,將文件路徑傳入
// 1.直接以文件形式實(shí)例化幀抓取器,此方式可以推送h264,ps碼流格式的MP4
// FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(MP4_FILE_PATH);
// 2.從文件中取流實(shí)例化幀抓取器,此方式只能推送ps碼流的MP4
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(pis,0);
long startTime = System.currentTimeMillis();
log.info("開始初始化幀抓取器");
// 下面兩行設(shè)置可加可不加
grabber.setOption("analyzeduration", "1000000");
// grabber.setFormat("h264");
// 初始化幀抓取器,例如數(shù)據(jù)結(jié)構(gòu)(時間戳、編碼器上下文、幀對象等),
// 如果入?yún)⒌扔趖rue,還會調(diào)用avformat_find_stream_info方法獲取流的信息,放入AVFormatContext類型的成員變量oc中
grabber.start(true);
// grabber.startUnsafe(true); // 也可以使用此方法
log.info("幀抓取器初始化完成,耗時[{}]毫秒", System.currentTimeMillis()-startTime);
// grabber.start方法中,初始化的解碼器信息存在放在grabber的成員變量oc中
AVFormatContext avFormatContext = grabber.getFormatContext();
// 文件內(nèi)有幾個媒體流(一般是視頻流+音頻流)
int streamNum = avFormatContext.nb_streams();
// 沒有媒體流就不用繼續(xù)了
if (streamNum<1) {
log.error("文件內(nèi)不存在媒體流");
return;
}
// 取得視頻的幀率
int frameRate = (int)grabber.getVideoFrameRate();
log.info("視頻幀率[{}],視頻時長[{}]秒,媒體流數(shù)量[{}]",
frameRate,
avFormatContext.duration()/1000000,
avFormatContext.nb_streams());
// 遍歷每一個流,檢查其類型
for (int i=0; i< streamNum; i++) {
AVStream avStream = avFormatContext.streams(i);
AVCodecParameters avCodecParameters = avStream.codecpar();
log.info("流的索引[{}],編碼器類型[{}],編碼器ID[{}]", i, avCodecParameters.codec_type(), avCodecParameters.codec_id());
}
// 視頻寬度
int frameWidth = grabber.getImageWidth();
// 視頻高度
int frameHeight = grabber.getImageHeight();
// 音頻通道數(shù)量
int audioChannels = grabber.getAudioChannels();
log.info("視頻寬度[{}],視頻高度[{}],音頻通道數(shù)[{}]",
frameWidth,
frameHeight,
audioChannels);
// 實(shí)例化FFmpegFrameRecorder,將SRS的推送地址傳入
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(pushAddress,
frameWidth,
frameHeight,
audioChannels);
// 設(shè)置編碼格式
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
// 設(shè)置封裝格式
recorder.setFormat("flv");
// 一秒內(nèi)的幀數(shù)
recorder.setFrameRate(frameRate);
// 兩個關(guān)鍵幀之間的幀數(shù)
recorder.setGopSize(frameRate);
// 設(shè)置音頻通道數(shù),與視頻源的通道數(shù)相等
recorder.setAudioChannels(grabber.getAudioChannels());
startTime = System.currentTimeMillis();
log.info("開始初始化幀抓取器");
// 初始化幀錄制器,例如數(shù)據(jù)結(jié)構(gòu)(音頻流、視頻流指針,編碼器),
// 調(diào)用av_guess_format方法,確定視頻輸出時的封裝方式,
// 媒體上下文對象的內(nèi)存分配,
// 編碼器的各項(xiàng)參數(shù)設(shè)置
recorder.start();
log.info("幀錄制初始化完成,耗時[{}]毫秒", System.currentTimeMillis()-startTime);
Frame frame;
startTime = System.currentTimeMillis();
log.info("開始推流");
long videoTS = 0;
int videoFrameNum = 0;
int audioFrameNum = 0;
int dataFrameNum = 0;
// 假設(shè)一秒鐘15幀,那么兩幀間隔就是(1000/15)毫秒
int interVal = 1000/frameRate;
// 發(fā)送完一幀后sleep的時間,不能完全等于(1000/frameRate),不然會卡頓,
// 要更小一些,這里取八分之一
interVal/=8;
// 持續(xù)從視頻源取幀
while (null!=(frame=grabber.grab())) {
videoTS = 1000 * (System.currentTimeMillis() - startTime);
// 時間戳
recorder.setTimestamp(videoTS);
// 有圖像,就把視頻幀加一
if (null!=frame.image) {
videoFrameNum++;
}
// 有聲音,就把音頻幀加一
if (null!=frame.samples) {
audioFrameNum++;
}
// 有數(shù)據(jù),就把數(shù)據(jù)幀加一
if (null!=frame.data) {
dataFrameNum++;
}
// 取出的每一幀,都推送到SRS
recorder.record(frame);
// 停頓一下再推送
Thread.sleep(interVal);
}
log.info("推送完成,視頻幀[{}],音頻幀[{}],數(shù)據(jù)幀[{}],耗時[{}]秒",
videoFrameNum,
audioFrameNum,
dataFrameNum,
(System.currentTimeMillis()-startTime)/1000);
// 關(guān)閉幀錄制器
recorder.close();
// 關(guān)閉幀抓取器
grabber.stop();
grabber.close();
pis.close();
}
}
其中,Thread.sleep(500);是必要的。要保證此線程執(zhí)行到后面代碼時,管道中必須存在流,這樣開始初始化幀抓取器才能成功。即取流線程必須先于推流線程執(zhí)行。否則會報(bào)錯。文章來源:http://www.zghlxwxcb.cn/news/detail-573232.html
3.部分代碼
代碼中涉及到部分業(yè)務(wù)代碼,按需修改。文章來源地址http://www.zghlxwxcb.cn/news/detail-573232.html
1.啟動項(xiàng)目初始化cms,stream的代碼
package com.ei.ambulance;
import com.ei.ambulance.mapper.BreastpieceMapper;
import com.ei.ambulance.mapper.BreastpieceVideoMapper;
import com.ei.ambulance.mapper.TaskDetailMapper;
import com.ei.ambulance.util.RedisUtil;
import com.ei.ambulance.util.cacheMap.CacheMap;
import com.ei.ambulance.util.isup.Cms;
import com.ei.ambulance.util.isup.Stream;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @author zhangyd
* @date 2022/9/20
*/
@Component
@Slf4j
@Order(1)
public class ISUPIniter implements CommandLineRunner {
@Value("${hik.cmsServerIP}")
String cmsServerIp;
@Value("${hik.cmsServerPort}")
String cmsServerPort;
@Value("${hik.voiceSmsServerIP}")
String voiceSmsServerIp;
@Value("${hik.voiceSmsServerPort}")
String voiceSmsServerPort;
@Value("${hik.breastpieceVideoPath}")
String breastpieceVideoPath;
@Value("${rtmp.rtmphost}")
private String rtmphost;
@Value("${hik.smsServerIP}")
String smsServerIP;
@Value("${hik.smsServerPort}")
String smsServerPort;
@Autowired
RedisUtil redisUtil;
@Autowired
BreastpieceMapper breastpieceMapper;
@Autowired
TaskDetailMapper taskDetailMapper;
@Autowired
BreastpieceVideoMapper breastpieceVideoMapper;
@Override
public void run(String... args) throws Exception {
Cms cms = new Cms();
cms.redisUtil = redisUtil;
cms.breastpieceMapper = breastpieceMapper;
cms.taskDetailMapper = taskDetailMapper;
cms.breastpieceVideoMapper = breastpieceVideoMapper;
cms.cMS_Init();
cms.startCmsListen(cmsServerIp, cmsServerPort, breastpieceVideoPath);
Stream stream = new Stream();
stream.eStream_Init();
stream.startRealPlayListen(smsServerIP, smsServerPort);
Stream.redisUtil = redisUtil;
Stream.rtmphost = rtmphost;
CacheMap.put("stream", stream);
CacheMap.put("cms", cms);
redisUtil.deletePattern("video:*");
}
}
2.cms代碼
package com.ei.ambulance.util.isup;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.ei.ambulance.mapper.BreastpieceMapper;
import com.ei.ambulance.mapper.BreastpieceVideoMapper;
import com.ei.ambulance.mapper.TaskDetailMapper;
import com.ei.ambulance.model.Breastpiece;
import com.ei.ambulance.model.BreastpieceVideo;
import com.ei.ambulance.model.ambulanceManage.TaskDetail;
import com.ei.ambulance.util.RedisUtil;
import com.ei.ambulance.util.Xml2JsonUtil;
import com.ei.ambulance.util.cacheMap.CacheMap;
import com.ei.ambulance.util.hik.OsSelect;
import com.ei.ambulance.vo.video.VideoFileInfoVo;
import com.ei.ambulance.vo.video.VideoFilesReq;
import com.sun.istack.internal.NotNull;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.DocumentException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author zhangyd
* @date 2022/9/20
*/
@Slf4j
public class Cms {
public static Map<String,Integer> userLoginMap = new HashMap<>();
public RedisUtil redisUtil;
public BreastpieceMapper breastpieceMapper;
public TaskDetailMapper taskDetailMapper;
public BreastpieceVideoMapper breastpieceVideoMapper;
public static HCISUPCMS hCEhomeCMS = null;
//CMS監(jiān)聽句柄
public static int CmsHandle = -1;
//注冊回調(diào)函數(shù)實(shí)現(xiàn)
static FRegisterCallBack fRegisterCallBack;
HCISUPCMS.NET_EHOME_CMS_LISTEN_PARAM struCMSListenPara = new HCISUPCMS.NET_EHOME_CMS_LISTEN_PARAM();
/**
* 根據(jù)不同操作系統(tǒng)選擇不同的庫文件和庫路徑
*
* @return
*/
private static boolean createSDKInstance() {
if (hCEhomeCMS == null) {
synchronized (HCISUPCMS.class) {
String strDllPath = "";
try {
if (OsSelect.isWindows()) {
//win系統(tǒng)加載庫路徑(路徑不要帶中文)
strDllPath = System.getProperty("user.dir") + "\\lib\\isupsdk\\HCISUPCMS.dll";
} else if (OsSelect.isLinux()) {
//Linux系統(tǒng)加載庫路徑(路徑不要帶中文)
strDllPath = System.getProperty("user.dir") + "/lib/isupsdkLinux/libHCISUPCMS.so";
log.info("===============1{}", strDllPath);
// strDllPath = "/usr/soft/java-service/ambulance/lib/isupsdkLinux/libHCISUPCMS.so";
}
hCEhomeCMS = (HCISUPCMS) Native.loadLibrary(strDllPath, HCISUPCMS.class);
} catch (Exception ex) {
log.info("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
return false;
}
}
}
return true;
}
/**
* cms服務(wù)初始化,開啟監(jiān)聽
*
* @throws IOException
*/
public void cMS_Init() throws IOException {
if (hCEhomeCMS == null) {
if (!createSDKInstance()) {
log.info("Load CMS SDK fail");
return;
}
}
if (OsSelect.isWindows()) {
HCISUPCMS.BYTE_ARRAY ptrByteArrayCrypto = new HCISUPCMS.BYTE_ARRAY(256);
String strPathCrypto = System.getProperty("user.dir") + "\\lib\\isupsdk\\libeay32.dll"; //Linux版本是libcrypto.so庫文件的路徑
System.arraycopy(strPathCrypto.getBytes(), 0, ptrByteArrayCrypto.byValue, 0, strPathCrypto.length());
ptrByteArrayCrypto.write();
hCEhomeCMS.NET_ECMS_SetSDKInitCfg(0, ptrByteArrayCrypto.getPointer());
//設(shè)置libssl.so所在路徑
HCISUPCMS.BYTE_ARRAY ptrByteArraySsl = new HCISUPCMS.BYTE_ARRAY(256);
String strPathSsl = System.getProperty("user.dir") + "\\lib\\isupsdk\\ssleay32.dll"; //Linux版本是libssl.so庫文件的路徑
System.arraycopy(strPathSsl.getBytes(), 0, ptrByteArraySsl.byValue, 0, strPathSsl.length());
ptrByteArraySsl.write();
hCEhomeCMS.NET_ECMS_SetSDKInitCfg(1, ptrByteArraySsl.getPointer());
//注冊服務(wù)初始化
boolean binit = hCEhomeCMS.NET_ECMS_Init();
//設(shè)置HCAapSDKCom組件庫文件夾所在路徑
HCISUPCMS.BYTE_ARRAY ptrByteArrayCom = new HCISUPCMS.BYTE_ARRAY(256);
String strPathCom = System.getProperty("user.dir") + "\\lib\\isupsdk\\HCAapSDKCom"; //只支持絕對路徑,建議使用英文路徑
System.arraycopy(strPathCom.getBytes(), 0, ptrByteArrayCom.byValue, 0, strPathCom.length());
ptrByteArrayCom.write();
hCEhomeCMS.NET_ECMS_SetSDKLocalCfg(5, ptrByteArrayCom.getPointer());
} else if (OsSelect.isLinux()) {
//todo linux版本的sdk
HCISUPCMS.BYTE_ARRAY ptrByteArrayCrypto = new HCISUPCMS.BYTE_ARRAY(256);
String strPathCrypto = System.getProperty("user.dir") + "/lib/isupsdkLinux/libcrypto.so"; //Linux版本是libcrypto.so庫文件的路徑
log.info("===============2{}", strPathCrypto);
System.arraycopy(strPathCrypto.getBytes(), 0, ptrByteArrayCrypto.byValue, 0, strPathCrypto.length());
ptrByteArrayCrypto.write();
hCEhomeCMS.NET_ECMS_SetSDKInitCfg(0, ptrByteArrayCrypto.getPointer());
//設(shè)置libssl.so所在路徑
HCISUPCMS.BYTE_ARRAY ptrByteArraySsl = new HCISUPCMS.BYTE_ARRAY(256);
String strPathSsl = System.getProperty("user.dir") + "/lib/isupsdkLinux/libssl.so"; //Linux版本是libssl.so庫文件的路徑
log.info("===============3{}", strPathSsl);
System.arraycopy(strPathSsl.getBytes(), 0, ptrByteArraySsl.byValue, 0, strPathSsl.length());
ptrByteArraySsl.write();
hCEhomeCMS.NET_ECMS_SetSDKInitCfg(1, ptrByteArraySsl.getPointer());
//注冊服務(wù)初始化
boolean binit = hCEhomeCMS.NET_ECMS_Init();
//設(shè)置HCAapSDKCom組件庫文件夾所在路徑
HCISUPCMS.BYTE_ARRAY ptrByteArrayCom = new HCISUPCMS.BYTE_ARRAY(256);
String strPathCom = System.getProperty("user.dir") + "/lib/isupsdkLinux/HCAapSDKCom/"; //只支持絕對路徑,建議使用英文路徑
log.info("===============4{}", strPathCom);
System.arraycopy(strPathCom.getBytes(), 0, ptrByteArrayCom.byValue, 0, strPathCom.length());
ptrByteArrayCom.write();
hCEhomeCMS.NET_ECMS_SetSDKLocalCfg(5, ptrByteArrayCom.getPointer());
}
hCEhomeCMS.NET_ECMS_SetLogToFile(3, System.getProperty("user.dir") + "/EHomeSDKLog", false);
}
public void startCmsListen(String cmsServerIp, String cmsServerPort, String breastpieceVideoPath) {
if (fRegisterCallBack == null) {
fRegisterCallBack = new FRegisterCallBack();
fRegisterCallBack.ip = cmsServerIp;
fRegisterCallBack.port = "8007";
fRegisterCallBack.breastpieceVideoPath = breastpieceVideoPath;
}
System.arraycopy(cmsServerIp.getBytes(), 0, struCMSListenPara.struAddress.szIP, 0, cmsServerIp.length());
struCMSListenPara.struAddress.wPort = Short.parseShort(cmsServerPort);
struCMSListenPara.fnCB = fRegisterCallBack;
struCMSListenPara.write();
//啟動監(jiān)聽,接收設(shè)備注冊信息
CmsHandle = hCEhomeCMS.NET_ECMS_StartListen(struCMSListenPara);
if (CmsHandle < -1) {
log.info("NET_ECMS_StartListen failed, error code:" + hCEhomeCMS.NET_ECMS_GetLastError());
hCEhomeCMS.NET_ECMS_Fini();
return;
}
String cmsListenInfo = new String(struCMSListenPara.struAddress.szIP).trim() + "_" + struCMSListenPara.struAddress.wPort;
log.info("注冊服務(wù)器:" + cmsListenInfo + ",NET_ECMS_StartListen succeed!\n");
}
public boolean setHeart(int lUserID, long dwKeepAliveSec, long dwTimeOutCount) {
boolean result = hCEhomeCMS.NET_ECMS_SetAliveTimeout(lUserID, dwKeepAliveSec, dwTimeOutCount);
if (result) {
log.info("device NET_ECMS_SetAliveTimeout success");
} else {
log.info("device NET_ECMS_SetAliveTimeout failed, error code: {}", hCEhomeCMS.NET_ECMS_GetLastError());
}
return result;
}
public String channels(int channel, int lUserID) throws DocumentException {
HCISUPCMS.NET_EHOME_PTXML_PARAM m_struParam = new HCISUPCMS.NET_EHOME_PTXML_PARAM();
m_struParam.read();
String url = "GET /ISAPI/ContentMgmt/InputProxy/channels";
HCISUPCMS.BYTE_ARRAY ptrUrl = new HCISUPCMS.BYTE_ARRAY(1024);
System.arraycopy(url.getBytes(), 0, ptrUrl.byValue, 0, url.length());
ptrUrl.write();
m_struParam.pRequestUrl = ptrUrl.getPointer();
m_struParam.dwRequestUrlLen = url.length();
HCISUPCMS.BYTE_ARRAY ptrOutByte = new HCISUPCMS.BYTE_ARRAY(100 * 1024);
m_struParam.pOutBuffer = ptrOutByte.getPointer();
m_struParam.dwOutSize = 100 * 1024;
m_struParam.write();
if (!hCEhomeCMS.NET_ECMS_ISAPIPassThrough(lUserID, m_struParam)) {
int iErr = hCEhomeCMS.NET_ECMS_GetLastError();
log.info("NET_ECMS_ISAPIPassThrough failed, error:{}", iErr);
m_struParam.read();
ptrOutByte.read();
log.info("ptrOutByte:{}", new String(ptrOutByte.byValue).trim());
}
String xml = new String(m_struParam.pOutBuffer.getByteArray(0, m_struParam.dwOutSize));
xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + xml;
JSONObject result = Xml2JsonUtil.xml2Json(xml);
JSONArray jsonArray = result.getJSONArray("inputproxychannel");
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject j = jsonArray.getJSONObject(i);
if (j.getInteger("id") == channel) {
return j.getJSONObject("sourceinputportdescriptor").getString("ipaddress");
}
}
return null;
}
public List<Integer> cameraList(int lUserID) throws DocumentException {
HCISUPCMS.NET_EHOME_PTXML_PARAM m_struParam = new HCISUPCMS.NET_EHOME_PTXML_PARAM();
m_struParam.read();
String url = "GET /ISAPI/ContentMgmt/InputProxy/channels";
HCISUPCMS.BYTE_ARRAY ptrUrl = new HCISUPCMS.BYTE_ARRAY(1024);
System.arraycopy(url.getBytes(), 0, ptrUrl.byValue, 0, url.length());
ptrUrl.write();
m_struParam.pRequestUrl = ptrUrl.getPointer();
m_struParam.dwRequestUrlLen = url.length();
HCISUPCMS.BYTE_ARRAY ptrOutByte = new HCISUPCMS.BYTE_ARRAY(100 * 1024);
m_struParam.pOutBuffer = ptrOutByte.getPointer();
m_struParam.dwOutSize = 100 * 1024;
m_struParam.write();
if (!hCEhomeCMS.NET_ECMS_ISAPIPassThrough(lUserID, m_struParam)) {
int iErr = hCEhomeCMS.NET_ECMS_GetLastError();
log.info("NET_ECMS_ISAPIPassThrough failed, error:{}", iErr);
m_struParam.read();
ptrOutByte.read();
log.info("ptrOutByte:{}", new String(ptrOutByte.byValue).trim());
}
String xml = new String(m_struParam.pOutBuffer.getByteArray(0, m_struParam.dwOutSize));
xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + xml;
JSONObject resultJson = Xml2JsonUtil.xml2Json(xml);
JSONArray jsonArray = resultJson.getJSONArray("inputproxychannel");
List<Integer> result = new ArrayList<>();
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject j = jsonArray.getJSONObject(i);
result.add(j.getInteger("id"));
}
return result;
}
public void playBack(int lUserID, String ip, String port, @NotNull Date start, @NotNull Date end, String fileName, Integer taskId, Integer breastpieceId) {
HCISUPCMS.NET_EHOME_PLAYBACK_INFO_IN pPlaybackInfoIn = new HCISUPCMS.NET_EHOME_PLAYBACK_INFO_IN();
pPlaybackInfoIn.read();
pPlaybackInfoIn.dwSize = pPlaybackInfoIn.size();
pPlaybackInfoIn.dwChannel = 1;
pPlaybackInfoIn.byPlayBackMode = 1;
pPlaybackInfoIn.unionPlayBackMode.setType(HCISUPCMS.NET_EHOME_PLAYBACKBYTIME.class);
Calendar cal = Calendar.getInstance();
cal.setTime(start);
pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStartTime.wYear = (short) cal.get(Calendar.YEAR);
pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStartTime.byMonth = (byte) (cal.get(Calendar.MONTH) + 1);
pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStartTime.byDay = (byte) cal.get(Calendar.DAY_OF_MONTH);
pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStartTime.byHour = (byte) cal.get(Calendar.HOUR_OF_DAY);
pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStartTime.byMinute = (byte) cal.get(Calendar.MINUTE);
pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStartTime.bySecond = (byte) cal.get(Calendar.SECOND);
cal.setTime(end);
pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStopTime.wYear = (short) cal.get(Calendar.YEAR);
pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStopTime.byMonth = (byte) (cal.get(Calendar.MONTH) + 1);
pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStopTime.byDay = (byte) cal.get(Calendar.DAY_OF_MONTH);
pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStopTime.byHour = (byte) cal.get(Calendar.HOUR_OF_DAY);
pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStopTime.byMinute = (byte) cal.get(Calendar.MINUTE);
pPlaybackInfoIn.unionPlayBackMode.struPlayBackbyTime.struStopTime.bySecond = (byte) cal.get(Calendar.SECOND);
System.arraycopy(ip.getBytes(), 0, pPlaybackInfoIn.struStreamSever.szIP, 0, ip.length());
pPlaybackInfoIn.struStreamSever.wPort = Short.parseShort(port);
pPlaybackInfoIn.write();
HCISUPCMS.NET_EHOME_PLAYBACK_INFO_OUT pPlaybackInfoOut = new HCISUPCMS.NET_EHOME_PLAYBACK_INFO_OUT();
pPlaybackInfoOut.write();
log.info("NET_ECMS_StartPlayBack接口參數(shù):{}", pPlaybackInfoIn);
if (hCEhomeCMS.NET_ECMS_StartPlayBack(lUserID, pPlaybackInfoIn, pPlaybackInfoOut)) {
pPlaybackInfoOut.read();
log.info("NET_ECMS_StartPlayBack success");
} else {
log.info("NET_ECMS_StartPlayBack failed, error code: {}", hCEhomeCMS.NET_ECMS_GetLastError());
return;
}
HCISUPCMS.NET_EHOME_PUSHPLAYBACK_IN m_struPushPlayBackIn = new HCISUPCMS.NET_EHOME_PUSHPLAYBACK_IN();
m_struPushPlayBackIn.read();
m_struPushPlayBackIn.dwSize = m_struPushPlayBackIn.size();
m_struPushPlayBackIn.lSessionID = pPlaybackInfoOut.lSessionID;
m_struPushPlayBackIn.write();
HCISUPCMS.NET_EHOME_PUSHPLAYBACK_OUT m_struPushPlayBackOut = new HCISUPCMS.NET_EHOME_PUSHPLAYBACK_OUT();
m_struPushPlayBackOut.read();
m_struPushPlayBackOut.dwSize = m_struPushPlayBackOut.size();
m_struPushPlayBackOut.write();
log.info("NET_ECMS_StartPushPlayBack接口參數(shù):{}", m_struPushPlayBackIn);
if (hCEhomeCMS.NET_ECMS_StartPushPlayBack(lUserID, m_struPushPlayBackIn, m_struPushPlayBackOut)) {
log.info("NET_ECMS_StartPushPlayBack success");
redisUtil.set("downloadHandle:" + m_struPushPlayBackOut.lHandle, fileName);
BreastpieceVideo breastpieceVideo = new BreastpieceVideo();
String[] names = fileName.split(OsSelect.isLinux()? "/" : "\\\\");
breastpieceVideo.setTaskId(taskId);
breastpieceVideo.setBreastpieceId(breastpieceId);
breastpieceVideo.setName(names[names.length - 1] + ".mp4");
breastpieceVideo.setAddress("http://47.101.185.231/ambulance-pc/video/breast/");
breastpieceVideo.setStartTime(start);
breastpieceVideo.setEndTime(end);
breastpieceVideoMapper.insert(breastpieceVideo);
} else {
log.info("NET_ECMS_StartPushPlayBack failed, error code: {}", hCEhomeCMS.NET_ECMS_GetLastError());
}
}
//注冊回調(diào)函數(shù)
public class FRegisterCallBack implements HCISUPCMS.DEVICE_REGISTER_CB {
public String ip, port, breastpieceVideoPath;
@Override
public boolean invoke(int lUserID, int dwDataType, Pointer pOutBuffer, int dwOutLen, Pointer pInBuffer, int dwInLen, Pointer pUser) {
log.info("FRegisterCallBack, dwDataType:" + dwDataType + ", lUserID:" + lUserID);
HCISUPCMS.NET_EHOME_DEV_REG_INFO_V12 strDevRegInfo;
Pointer pDevRegInfo;
if (dwDataType == 0 || dwDataType == 7) {
strDevRegInfo = new HCISUPCMS.NET_EHOME_DEV_REG_INFO_V12();
strDevRegInfo.write();
pDevRegInfo = strDevRegInfo.getPointer();
pDevRegInfo.write(0, pOutBuffer.getByteArray(0, strDevRegInfo.size()), 0, strDevRegInfo.size());
strDevRegInfo.read();
HCISUPCMS.NET_EHOME_SERVER_INFO_V50 strEhomeServerInfo = new HCISUPCMS.NET_EHOME_SERVER_INFO_V50();
strEhomeServerInfo.read();
byte[] byCmsIP = new byte[0];
log.info(new String(byCmsIP));
String nvrCode = new String(strDevRegInfo.struRegInfo.byDeviceID).trim();
String nvrIp = new String(strDevRegInfo.struRegInfo.struDevAdd.szIP).trim();
log.info("Device online, DeviceID is:" + nvrCode);
log.info("Device online, DeviceIP is:" + nvrIp);
// 設(shè)備注冊上線標(biāo)志
userLoginMap.put(nvrCode,lUserID);
redisUtil.set("ip:" + nvrCode, nvrIp);
redisUtil.set("lUserID:" + nvrCode, lUserID);
redisUtil.set("carNo:" + lUserID, nvrCode);
if (nvrCode.startsWith("xp")) {
UpdateWrapper<Breastpiece> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("name", nvrCode);
Breastpiece breastpiece = new Breastpiece();
breastpiece.setIsOnline(1);
breastpieceMapper.update(breastpiece, updateWrapper);
QueryWrapper<Breastpiece> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", nvrCode);
Breastpiece breastpieceL = breastpieceMapper.selectOne(queryWrapper);
//異步配置心跳監(jiān)聽。100秒沒有收到心跳,設(shè)備離線
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(() -> {
try {
Thread.sleep(2000);
boolean heart = hCEhomeCMS.NET_ECMS_SetAliveTimeout(lUserID, 100L, 1L);
if (heart) {
log.info("device {} NET_ECMS_SetAliveTimeout success", nvrCode);
} else {
log.info("device {} NET_ECMS_SetAliveTimeout failed, error code: {}", nvrCode, hCEhomeCMS.NET_ECMS_GetLastError());
}
Stream stream = CacheMap.get("stream");
stream.startListenPlayBack(ip, port);
List<TaskDetail> taskList = taskDetailMapper.selectListByDeviceCode(nvrCode);
if (taskList != null && taskList.size() > 0) {
taskList.forEach(t -> {
QueryWrapper<BreastpieceVideo> wrapper = new QueryWrapper<>();
wrapper.eq("task_id", t.getId());
Integer c = breastpieceVideoMapper.selectCount(wrapper);
if (c <= 0) {
playBack(lUserID, "47.101.185.231", port, t.getReceiveTime(), t.getDeliveryTime(), breastpieceVideoPath + t.getId(), t.getId(), breastpieceL.getId());
}
});
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
executorService.shutdown();
}
return true;
} else if (dwDataType == 3) {
strDevRegInfo = new HCISUPCMS.NET_EHOME_DEV_REG_INFO_V12();
strDevRegInfo.write();
pDevRegInfo = strDevRegInfo.getPointer();
pDevRegInfo.write(0, pOutBuffer.getByteArray(0, strDevRegInfo.size()), 0, strDevRegInfo.size());
strDevRegInfo.read();
String szEHomeKey = "12345678";
byte[] bs = szEHomeKey.getBytes();
pInBuffer.write(0, bs, 0, szEHomeKey.length());
} else if (dwDataType == 4) {
strDevRegInfo = new HCISUPCMS.NET_EHOME_DEV_REG_INFO_V12();
strDevRegInfo.write();
pDevRegInfo = strDevRegInfo.getPointer();
pDevRegInfo.write(0, pOutBuffer.getByteArray(0, strDevRegInfo.size()), 0, strDevRegInfo.size());
strDevRegInfo.read();
log.info("byDeviceID:" + new String(strDevRegInfo.struRegInfo.byDeviceID).trim());
log.info("bySessionKey:" + new String(strDevRegInfo.struRegInfo.bySessionKey).trim());
HCISUPCMS.NET_EHOME_DEV_SESSIONKEY struSessionKey = new HCISUPCMS.NET_EHOME_DEV_SESSIONKEY();
System.arraycopy(strDevRegInfo.struRegInfo.byDeviceID, 0, struSessionKey.sDeviceID, 0, strDevRegInfo.struRegInfo.byDeviceID.length);
System.arraycopy(strDevRegInfo.struRegInfo.bySessionKey, 0, struSessionKey.sSessionKey, 0, strDevRegInfo.struRegInfo.bySessionKey.length);
struSessionKey.write();
Pointer pSessionKey = struSessionKey.getPointer();
hCEhomeCMS.NET_ECMS_SetDeviceSessionKey(pSessionKey);
// mHCEHomeAlarm.NET_EALARM_SetDeviceSessionKey(pSessionKey);
} else if (dwDataType == 5) {
String dasInfo = "{\n" +
" \"Type\":\"DAS\",\n" +
" \"DasInfo\":{\n" +
" \"Address\":\"47.101.185.231\",\n" +
" \"Domain\":\"\",\n" +
" \"ServerID\":\"\",\n" +
" \"Port\":20000,\n" +
" \"UdpPort\":\n" +
" }\n" +
"}";
byte[] bs1 = dasInfo.getBytes();
pInBuffer.write(0, bs1, 0, dasInfo.length());
} else if (dwDataType == 1) {
//設(shè)備離線
String deviceName = redisUtil.get("carNo:" + lUserID);
log.info("設(shè)備{}離線", deviceName);
if (deviceName.startsWith("xp")) {
//胸牌
UpdateWrapper<Breastpiece> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("name", deviceName);
Breastpiece breastpiece = new Breastpiece();
breastpiece.setIsOnline(0);
breastpieceMapper.update(breastpiece, updateWrapper);
}
redisUtil.delete("carNo:" + lUserID);
redisUtil.delete("ip:" + deviceName);
redisUtil.delete("lUserID:" + deviceName);
userLoginMap.remove(deviceName);
} else if (dwDataType == 8) {
//心跳
log.info("__心跳___");
log.info("FRegisterCallBack default type:" + dwDataType);
} else {
log.info("FRegisterCallBack default type:" + dwDataType);
}
return true;
}
}
public List<VideoFileInfoVo> findFile(int lLoginID, VideoFilesReq req) throws InterruptedException {
List<VideoFileInfoVo> result = new ArrayList<>();
HCISUPCMS.NET_EHOME_REC_FILE_COND strufindCond = new HCISUPCMS.NET_EHOME_REC_FILE_COND();
strufindCond.dwChannel = 1;
strufindCond.dwRecType = 0xff;
strufindCond.dwStartIndex = 0;
strufindCond.dwMaxFileCountPer = 10;
Calendar c = Calendar.getInstance();
c.setTime(req.getStart());
strufindCond.struStartTime.wYear = (short) c.get(Calendar.YEAR);
strufindCond.struStartTime.byMonth = (byte) (c.get(Calendar.MONTH) + 1);
strufindCond.struStartTime.byDay = (byte) c.get(Calendar.DAY_OF_MONTH);
strufindCond.struStartTime.byHour = (byte) c.get(Calendar.HOUR_OF_DAY);
strufindCond.struStartTime.byMinute = (byte) c.get(Calendar.MINUTE);
strufindCond.struStartTime.bySecond = (byte) c.get(Calendar.SECOND);
c.setTime(req.getEnd());
strufindCond.struStopTime.wYear = (short) c.get(Calendar.YEAR);
strufindCond.struStopTime.byMonth = (byte) (c.get(Calendar.MONTH) + 1);
strufindCond.struStopTime.byDay = (byte) c.get(Calendar.DAY_OF_MONTH);
strufindCond.struStopTime.byHour = (byte) c.get(Calendar.HOUR_OF_DAY);
strufindCond.struStopTime.byMinute = (byte) c.get(Calendar.MINUTE);
strufindCond.struStopTime.bySecond = (byte) c.get(Calendar.SECOND);
int lHandle = hCEhomeCMS.NET_ECMS_StartFindFile_V11(lLoginID, 0, strufindCond, strufindCond.size());
if (lHandle < 0) {
log.info("NET_ECMS_StartFindFile_V11 failed, error code: {}", hCEhomeCMS.NET_ECMS_GetLastError());
} else {
log.info("NET_ECMS_StartFindFile_V11 success!");
while (true) {
HCISUPCMS.NET_EHOME_REC_FILE struFileInfo = new HCISUPCMS.NET_EHOME_REC_FILE();
int lRet = hCEhomeCMS.NET_ECMS_FindNextFile_V11(lHandle, struFileInfo, struFileInfo.size());
if (lRet == 1000) {
//保存獲取到的文件
VideoFileInfoVo vo = new VideoFileInfoVo();
vo.setFileName(new String(struFileInfo.sFileName));
log.info(vo.getFileName());
String fileSize;
if (struFileInfo.dwFileSize / 1024 == 0) {
fileSize = String.valueOf(struFileInfo.dwFileSize);
} else if (struFileInfo.dwFileSize / 1024 > 0 && struFileInfo.dwFileSize / (1024 * 1024) == 0) {
fileSize = struFileInfo.dwFileSize / 1024 + "K";
} else {
fileSize = struFileInfo.dwFileSize / (1024 * 1024) + "M";
}
vo.setSize(fileSize);
vo.setStart(String.format("%04d-%02d-%02d %02d:%02d:%02d", struFileInfo.struStartTime.wYear, struFileInfo.struStartTime.byMonth, struFileInfo.struStartTime.byDay, struFileInfo.struStartTime.byHour, struFileInfo.struStartTime.byMinute, struFileInfo.struStartTime.bySecond));
vo.setEnd(String.format("%04d-%02d-%02d %02d:%02d:%02d", struFileInfo.struStopTime.wYear, struFileInfo.struStopTime.byMonth, struFileInfo.struStopTime.byDay, struFileInfo.struStopTime.byHour, struFileInfo.struStopTime.byMinute, struFileInfo.struStopTime.bySecond));
result.add(vo);
} else if (lRet == 1002) {
Thread.sleep(5L);
} else {
break;
}
}
hCEhomeCMS.NET_ECMS_StopFindFile(lHandle);
}
return result;
}
}
3.stream代碼
package com.ei.ambulance.util.isup;
import com.ei.ambulance.util.RedisUtil;
import com.ei.ambulance.util.hik.HCNetSDK;
import com.ei.ambulance.util.hik.OsSelect;
import com.ei.ambulance.util.video.PushUtil;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import lombok.extern.slf4j.Slf4j;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
@Slf4j
public class Stream {
public static Map<String,PipedOutputStream> streamMap = new HashMap<>();
public static RedisUtil redisUtil;
public static String rtmphost;
public static HCISUPStream hCEhomeStream = null;
public static PlayCtrl playCtrl = null;
static int m_lPlayBackLinkHandle = -1; //回放句柄
public static int m_lPlayBackListenHandle = -1; //回放監(jiān)聽句柄
public static int StreamHandle = -1; //預(yù)覽監(jiān)聽句柄
public static Map<String,Integer> sessionMap = new HashMap<>(); //預(yù)覽sessionID
public static Map<String,Integer> playHandleMap = new HashMap<>();
static int backSessionID = -1; //回放sessionID
static int Count = 0;
static int iCount = 0;
static IntByReference m_lPort = new IntByReference(-1);//回調(diào)預(yù)覽時播放庫端口指針
HCISUPStream.NET_EHOME_PLAYBACK_LISTEN_PARAM struPlayBackListen = new HCISUPStream.NET_EHOME_PLAYBACK_LISTEN_PARAM();
// HCISUPStream.NET_EHOME_LISTEN_PREVIEW_CFG struPreviewListen = new HCISUPStream.NET_EHOME_LISTEN_PREVIEW_CFG();
static FPREVIEW_NEWLINK_CB fPREVIEW_NEWLINK_CB;//預(yù)覽監(jiān)聽回調(diào)函數(shù)實(shí)現(xiàn)
// static FPREVIEW_DATA_CB fPREVIEW_DATA_CB;//預(yù)覽回調(diào)函數(shù)實(shí)現(xiàn)
public static Map<String,FPREVIEW_DATA_CB> dataMap = new HashMap<>();
static PLAYBACK_NEWLINK_CB fPLAYBACK_NEWLINK_CB; //回放監(jiān)聽回調(diào)函數(shù)實(shí)現(xiàn)
static PLAYBACK_DATA_CB fPLAYBACK_DATA_CB; //回放回調(diào)實(shí)現(xiàn)
/**
* 動態(tài)庫加載
*
* @return
*/
private static boolean CreateSDKInstance() {
if (hCEhomeStream == null) {
synchronized (HCISUPStream.class) {
String strDllPath = "";
try {
if (OsSelect.isWindows())
//win系統(tǒng)加載庫路徑
strDllPath = System.getProperty("user.dir") + "\\lib\\isupsdk\\HCISUPStream.dll";
else if (OsSelect.isLinux())
//Linux系統(tǒng)加載庫路徑
strDllPath = System.getProperty("user.dir") + "/lib/isupsdkLinux/libHCISUPStream.so";
hCEhomeStream = (HCISUPStream) Native.loadLibrary(strDllPath, HCISUPStream.class);
} catch (Exception ex) {
log.info("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
return false;
}
}
}
return true;
}
public void eStream_Init() {
if (hCEhomeStream == null) {
if (!CreateSDKInstance()) {
log.info("Load Stream SDK fail");
return;
} else {
log.info("Load Stream SDK success");
}
}
// if (playCtrl == null) {
// if (!CreatePlayInstance()) {
// log.info("Load PlayCtrl fail");
// return;
// } else {
// log.info("Load PlayCtrl SDK success");
// }
//
// }
if (OsSelect.isWindows()) {
HCISUPCMS.BYTE_ARRAY ptrByteArrayCrypto = new HCISUPCMS.BYTE_ARRAY(256);
String strPathCrypto = System.getProperty("user.dir") + "\\lib\\isupsdk\\libeay32.dll"; //Linux版本是libcrypto.so庫文件的路徑
System.arraycopy(strPathCrypto.getBytes(), 0, ptrByteArrayCrypto.byValue, 0, strPathCrypto.length());
ptrByteArrayCrypto.write();
if (!hCEhomeStream.NET_ESTREAM_SetSDKInitCfg(0, ptrByteArrayCrypto.getPointer())) {
log.info("NET_ESTREAM_SetSDKInitCfg 0 failed, error:" + hCEhomeStream.NET_ESTREAM_GetLastError());
}
HCISUPCMS.BYTE_ARRAY ptrByteArraySsl = new HCISUPCMS.BYTE_ARRAY(256);
String strPathSsl = System.getProperty("user.dir") + "\\lib\\isupsdk\\ssleay32.dll"; //Linux版本是libssl.so庫文件的路徑
System.arraycopy(strPathSsl.getBytes(), 0, ptrByteArraySsl.byValue, 0, strPathSsl.length());
ptrByteArraySsl.write();
if (!hCEhomeStream.NET_ESTREAM_SetSDKInitCfg(1, ptrByteArraySsl.getPointer())) {
log.info("NET_ESTREAM_SetSDKInitCfg 1 failed, error:" + hCEhomeStream.NET_ESTREAM_GetLastError());
}
//流媒體初始化
hCEhomeStream.NET_ESTREAM_Init();
//設(shè)置HCAapSDKCom組件庫文件夾所在路徑
HCISUPCMS.BYTE_ARRAY ptrByteArrayCom = new HCISUPCMS.BYTE_ARRAY(256);
String strPathCom = System.getProperty("user.dir") + "\\lib\\isupsdk\\HCAapSDKCom"; //只支持絕對路徑,建議使用英文路徑
System.arraycopy(strPathCom.getBytes(), 0, ptrByteArrayCom.byValue, 0, strPathCom.length());
ptrByteArrayCom.write();
if (!hCEhomeStream.NET_ESTREAM_SetSDKLocalCfg(5, ptrByteArrayCom.getPointer())) {
log.info("NET_ESTREAM_SetSDKLocalCfg 5 failed, error:" + hCEhomeStream.NET_ESTREAM_GetLastError());
}
hCEhomeStream.NET_ESTREAM_SetLogToFile(3, System.getProperty("user.dir") + "/EHomeSDKLog", false);
} else if (OsSelect.isLinux()) {
//設(shè)置libcrypto.so所在路徑
HCISUPCMS.BYTE_ARRAY ptrByteArrayCrypto = new HCISUPCMS.BYTE_ARRAY(256);
String strPathCrypto = System.getProperty("user.dir") + "/lib/libcrypto.so"; //Linux版本是libcrypto.so庫文件的路徑
System.arraycopy(strPathCrypto.getBytes(), 0, ptrByteArrayCrypto.byValue, 0, strPathCrypto.length());
ptrByteArrayCrypto.write();
if (!hCEhomeStream.NET_ESTREAM_SetSDKInitCfg(0, ptrByteArrayCrypto.getPointer())) {
log.info("NET_ESTREAM_SetSDKInitCfg 0 failed, error:" + hCEhomeStream.NET_ESTREAM_GetLastError());
}
//設(shè)置libssl.so所在路徑
HCISUPCMS.BYTE_ARRAY ptrByteArraySsl = new HCISUPCMS.BYTE_ARRAY(256);
String strPathSsl = System.getProperty("user.dir") + "/lib/libssl.so"; //Linux版本是libssl.so庫文件的路徑
System.arraycopy(strPathSsl.getBytes(), 0, ptrByteArraySsl.byValue, 0, strPathSsl.length());
ptrByteArraySsl.write();
if (!hCEhomeStream.NET_ESTREAM_SetSDKInitCfg(1, ptrByteArraySsl.getPointer())) {
log.info("NET_ESTREAM_SetSDKInitCfg 1 failed, error:" + hCEhomeStream.NET_ESTREAM_GetLastError());
}
hCEhomeStream.NET_ESTREAM_Init();
//設(shè)置HCAapSDKCom組件庫文件夾所在路徑
HCISUPCMS.BYTE_ARRAY ptrByteArrayCom = new HCISUPCMS.BYTE_ARRAY(256);
String strPathCom = System.getProperty("user.dir") + "/lib/HCAapSDKCom/"; //只支持絕對路徑,建議使用英文路徑
System.arraycopy(strPathCom.getBytes(), 0, ptrByteArrayCom.byValue, 0, strPathCom.length());
ptrByteArrayCom.write();
if (!hCEhomeStream.NET_ESTREAM_SetSDKLocalCfg(5, ptrByteArrayCom.getPointer())) {
log.info("NET_ESTREAM_SetSDKLocalCfg 5 failed, error:" + hCEhomeStream.NET_ESTREAM_GetLastError());
}
hCEhomeStream.NET_ESTREAM_SetLogToFile(3, System.getProperty("user.dir") + "/EHomeSDKLog", false);
}
}
public void startRealPlayListen(String smsServerListenIP, String smsServerListenPort) {
//預(yù)覽監(jiān)聽
if (fPREVIEW_NEWLINK_CB == null) {
fPREVIEW_NEWLINK_CB = new FPREVIEW_NEWLINK_CB();
}
HCISUPStream.NET_EHOME_LISTEN_PREVIEW_CFG struPreviewListen = new HCISUPStream.NET_EHOME_LISTEN_PREVIEW_CFG();
System.arraycopy(smsServerListenIP.getBytes(), 0, struPreviewListen.struIPAdress.szIP, 0, smsServerListenIP.length());
struPreviewListen.struIPAdress.wPort = Short.parseShort(smsServerListenPort); //流媒體服務(wù)器監(jiān)聽端口
struPreviewListen.fnNewLinkCB = fPREVIEW_NEWLINK_CB; //預(yù)覽連接請求回調(diào)函數(shù)
struPreviewListen.pUser = null;
struPreviewListen.byLinkMode = 0; //0- TCP方式,1- UDP方式
struPreviewListen.write();
if (StreamHandle < 0) {
StreamHandle = hCEhomeStream.NET_ESTREAM_StartListenPreview(struPreviewListen);
if (StreamHandle == -1) {
System.out.println("NET_ESTREAM_StartListenPreview failed, error code:" + hCEhomeStream.NET_ESTREAM_GetLastError());
hCEhomeStream.NET_ESTREAM_Fini();
return;
} else {
String StreamListenInfo = new String(struPreviewListen.struIPAdress.szIP).trim() + "_" + struPreviewListen.struIPAdress.wPort;
System.out.println("流媒體服務(wù):" + StreamListenInfo + ",NET_ESTREAM_StartListenPreview succeed");
}
}
}
/**
* 開啟預(yù)覽,
*
* @param carId
* @param lChannel 預(yù)覽通道號
*/
public void realPlay(int lLoginId, String carId, int lChannel, String smsServerIP, String smsServerPort) throws Exception {
// JPanelDemo.jRealWinInit();
HCISUPCMS.NET_EHOME_PREVIEWINFO_IN_V11 struPreviewIn = new HCISUPCMS.NET_EHOME_PREVIEWINFO_IN_V11();
struPreviewIn.iChannel = lChannel; //通道號
struPreviewIn.dwLinkMode = 0; //0- TCP方式,1- UDP方式
struPreviewIn.dwStreamType = 0; //碼流類型:0- 主碼流,1- 子碼流, 2- 第三碼流
struPreviewIn.struStreamSever.szIP = smsServerIP.getBytes();//流媒體服務(wù)器IP地址,公網(wǎng)地址
struPreviewIn.struStreamSever.wPort = Short.parseShort(smsServerPort); //流媒體服務(wù)器端口,需要跟服務(wù)器啟動監(jiān)聽端口一致
struPreviewIn.write();
//預(yù)覽請求
HCISUPCMS.NET_EHOME_PREVIEWINFO_OUT struPreviewOut = new HCISUPCMS.NET_EHOME_PREVIEWINFO_OUT();
boolean getRS = Cms.hCEhomeCMS.NET_ECMS_StartGetRealStreamV11(lLoginId, struPreviewIn, struPreviewOut);
// boolean getRS = Cms.hCEhomeCMS.NET_ECMS_StartGetRealStream(Cms.lLoginID, struPreviewIn, struPreviewOut);
//Thread.sleep(10000);
if (!getRS) {
log.error("NET_ECMS_StartGetRealStream failed, error code:{}", Cms.hCEhomeCMS.NET_ECMS_GetLastError());
throw new Exception("攝像頭不存在");
} else {
struPreviewOut.read();
log.info("NET_ECMS_StartGetRealStream succeed, sessionID:{}", struPreviewOut.lSessionID);
sessionMap.put("session:"+carId+"_"+lChannel,struPreviewOut.lSessionID);
}
HCISUPCMS.NET_EHOME_PUSHSTREAM_IN struPushInfoIn = new HCISUPCMS.NET_EHOME_PUSHSTREAM_IN();
struPushInfoIn.read();
struPushInfoIn.dwSize = struPushInfoIn.size();
struPushInfoIn.lSessionID = sessionMap.get("session:"+carId+"_"+lChannel);
struPushInfoIn.write();
HCISUPCMS.NET_EHOME_PUSHSTREAM_OUT struPushInfoOut = new HCISUPCMS.NET_EHOME_PUSHSTREAM_OUT();
struPushInfoOut.read();
struPushInfoOut.dwSize = struPushInfoOut.size();
struPushInfoOut.write();
if (!Cms.hCEhomeCMS.NET_ECMS_StartPushRealStream(lLoginId, struPushInfoIn, struPushInfoOut)) {
sessionMap.remove("session:"+carId+"_"+lChannel);
log.error("NET_ECMS_StartPushRealStream failed, error code:" + Cms.hCEhomeCMS.NET_ECMS_GetLastError());
} else {
log.info("NET_ECMS_StartPushRealStream succeed, sessionID:" + struPushInfoIn.lSessionID);
}
}
/**
* 停止預(yù)覽,Stream服務(wù)停止實(shí)時流轉(zhuǎn)發(fā),CMS向設(shè)備發(fā)送停止預(yù)覽請求
*/
public void StopRealPlay(String carNo, Integer channel) {
Integer lPreviewHandle = playHandleMap.get("realPlayHandle:" + carNo+channel);
if (lPreviewHandle == null) {
return;
}
if (!hCEhomeStream.NET_ESTREAM_StopPreview(lPreviewHandle)) {
System.out.println("NET_ESTREAM_StopPreview failed,err = " + hCEhomeStream.NET_ESTREAM_GetLastError());
return;
}
Integer loginId = Cms.userLoginMap.get(carNo);
if (loginId == null) {
return;
}
Integer sessionId = sessionMap.get("session:"+carNo+"_"+channel);
if (sessionId == null) {
return;
}
if (!Cms.hCEhomeCMS.NET_ECMS_StopGetRealStream(loginId, sessionId)) {
log.info("NET_ECMS_StopGetRealStream failed,err = " + Cms.hCEhomeCMS.NET_ECMS_GetLastError());
return;
}
log.info("停止Stream的實(shí)時流轉(zhuǎn)發(fā)");
Stream.dataMap.remove(carNo + "_" + channel);
Stream.sessionMap.remove("session:"+carNo+"_"+channel);
PipedOutputStream pos = streamMap.get("stream:" + lPreviewHandle);
if (pos != null) {
try {
pos.close();
} catch (IOException exception) {
exception.printStackTrace();
}
Stream.streamMap.remove("stream:"+ lPreviewHandle);
Stream.playHandleMap.remove("realPlayHandle:" + carNo+channel);
}
log.info("CMS發(fā)送預(yù)覽停止請求");
}
/**
* 播放庫加載
*
* @return
*/
private static boolean CreatePlayInstance() {
if (playCtrl == null) {
synchronized (PlayCtrl.class) {
String strPlayPath = "";
try {
if (OsSelect.isWindows())
//win系統(tǒng)加載庫路徑(路徑不要帶中文)
strPlayPath = System.getProperty("user.dir") + "\\lib\\isupsdk\\PlayCtrl.dll";
else if (OsSelect.isLinux())
//Linux系統(tǒng)加載庫路徑(路徑不要帶中文)
strPlayPath = System.getProperty("user.dir") + "/lib/libPlayCtrl.so";
playCtrl = (PlayCtrl) Native.loadLibrary(strPlayPath, PlayCtrl.class);
} catch (Exception ex) {
log.info("loadLibrary: " + strPlayPath + " Error: " + ex.getMessage());
return false;
}
}
}
return true;
}
public void startListenPlayBack(String ip, String port) {
if (fPLAYBACK_NEWLINK_CB == null) {
fPLAYBACK_NEWLINK_CB = new PLAYBACK_NEWLINK_CB();
}
HCISUPStream.NET_EHOME_PLAYBACK_LISTEN_PARAM param = new HCISUPStream.NET_EHOME_PLAYBACK_LISTEN_PARAM();
System.arraycopy(ip.getBytes(), 0, param.struIPAdress.szIP, 0, ip.length());
param.struIPAdress.wPort = Short.parseShort(port);
param.fnNewLinkCB = fPLAYBACK_NEWLINK_CB;
param.byLinkMode = 0;//tcp-0;udp-1
m_lPlayBackListenHandle = hCEhomeStream.NET_ESTREAM_StartListenPlayBack(param);
if (m_lPlayBackListenHandle < -1) {
log.info("NET_ESTREAM_StartListenPlayBack failed, error code: {}", hCEhomeStream.NET_ESTREAM_GetLastError());
} else {
log.info("回放服務(wù):{}_{}, NET_ESTREAM_StartListenPlayBack success", ip, port);
}
}
public class FPREVIEW_NEWLINK_CB implements HCISUPStream.PREVIEW_NEWLINK_CB {
@Override
public boolean invoke(int lLinkHandle, HCISUPStream.NET_EHOME_NEWLINK_CB_MSG pNewLinkCBMsg, Pointer pUserData) throws IOException {
// 監(jiān)聽,每realPlay調(diào)用時,此方法監(jiān)聽到,開始執(zhí)行
String userId = new String(pNewLinkCBMsg.szDeviceID).trim();
int dwChannelNo = pNewLinkCBMsg.dwChannelNo;
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream();
Stream.streamMap.put("stream:"+lLinkHandle,pos);
pos.connect(pis);
CompletableFuture.runAsync(()-> {
try {
PushUtil.grabAndPushRtmp(pis,"rtmp://"+rtmphost+"/live/"+userId+"_"+ dwChannelNo);
} catch (Exception e) {
e.printStackTrace();
}
}, Executors.newFixedThreadPool(1));
log.info("FPREVIEW_NEWLINK_CB callback");
log.info("FPREVIEW_NEWLINK_CB callback byStreamType : {}", pNewLinkCBMsg.byStreamType);
//預(yù)覽數(shù)據(jù)回調(diào)參數(shù)
playHandleMap.put("realPlayHandle:" + userId + dwChannelNo , lLinkHandle );
HCISUPStream.NET_EHOME_PREVIEW_DATA_CB_PARAM struDataCB = new HCISUPStream.NET_EHOME_PREVIEW_DATA_CB_PARAM();
FPREVIEW_DATA_CB fPREVIEW_DATA_CB = dataMap.get(userId + "_" + dwChannelNo);
if (fPREVIEW_DATA_CB == null) {
fPREVIEW_DATA_CB = new FPREVIEW_DATA_CB(pos);
dataMap.put(userId + "_" + dwChannelNo,fPREVIEW_DATA_CB);
}
struDataCB.fnPreviewDataCB = fPREVIEW_DATA_CB;
if (!hCEhomeStream.NET_ESTREAM_SetPreviewDataCB(lLinkHandle, struDataCB)) {
log.info("NET_ESTREAM_SetPreviewDataCB failed err::" + hCEhomeStream.NET_ESTREAM_GetLastError());
return false;
}
return true;
}
}
public class FPREVIEW_DATA_CB implements HCISUPStream.PREVIEW_DATA_CB {
private PipedOutputStream pos;
public FPREVIEW_DATA_CB(PipedOutputStream pos) {
this.pos = pos;
}
//實(shí)時流回調(diào)函數(shù)/
@Override
public void invoke(int iPreviewHandle, HCISUPStream.NET_EHOME_PREVIEW_CB_MSG pPreviewCBMsg, Pointer pUserData) throws Exception {
// if (Count == 500) {//降低打印頻率
// log.info("FPREVIEW_DATA_CB callback, iPreviewHandle:{}", iPreviewHandle);
// log.info("FPREVIEW_DATA_CB callback, data length:" + pPreviewCBMsg.dwDataLen);
// Count = 0;
// }
// Count++;
long offset = 0;
ByteBuffer buffers = pPreviewCBMsg.pRecvdata.getByteBuffer(offset, pPreviewCBMsg.dwDataLen);
byte[] bytes = new byte[pPreviewCBMsg.dwDataLen];
buffers.rewind();
buffers.get(bytes);
try{
//2.將數(shù)據(jù)讀入到內(nèi)存空間,此處不可用redis,否則執(zhí)行時間是當(dāng)前10倍
// PipedOutputStream pos = Stream.streamMap.get("stream:"+iPreviewHandle);
pos.write(bytes);
} catch (Exception e) {
e.printStackTrace();
}
}
}
byte[] allEsBytes = null;
public void writeESH264(final byte[] outputData) throws IOException {
if (outputData.length <= 0) {
return;
}
if ((outputData[0] & 0xff) == 0x00
&& (outputData[1] & 0xff) == 0x00
&& (outputData[2] & 0xff) == 0x01
&& (outputData[3] & 0xff) == 0xBA) {
if (allEsBytes != null && allEsBytes.length > 0) {
return;
// allEsBytes = null;
}
}
if ((outputData[0] & 0xff) == 0x00
&& (outputData[1] & 0xff) == 0x00
&& (outputData[2] & 0xff) == 0x01
&& (outputData[3] & 0xff) == 0xE0) {
int from = 9 + outputData[8] & 0xff;
int len = outputData.length - 9 - (outputData[8] & 0xff);
byte[] esBytes = new byte[len];
System.arraycopy(outputData, from, esBytes, 0, len);
if (allEsBytes == null) {
allEsBytes = esBytes;
} else {
byte[] newEsBytes = new byte[allEsBytes.length + esBytes.length];
System.arraycopy(allEsBytes, 0, newEsBytes, 0, allEsBytes.length);
System.arraycopy(esBytes, 0, newEsBytes, allEsBytes.length, esBytes.length);
allEsBytes = newEsBytes;
}
} else {
allEsBytes = outputData;
}
}
void ffmpegConvetor(String videoInputPath, String videoOutPath) throws Exception {
if (OsSelect.isWindows()) {
String ffmpegExe = "E:\\chromeDowload\\ffmpeg.exe";
List<String> command = new ArrayList<>();
command.add(ffmpegExe);
command.add("-i");
command.add(videoInputPath);
command.add("-c");
command.add("copy");
command.add("-an");
command.add(videoOutPath);
ProcessBuilder builder = new ProcessBuilder(command);
Process process = null;
try {
process = builder.start();
} catch (IOException e) {
e.printStackTrace();
}
// 使用這種方式會在瞬間大量消耗CPU和內(nèi)存等系統(tǒng)資源,所以這里我們需要對流進(jìn)行處理
try {
InputStream errorStream = process.getErrorStream();
InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
BufferedReader br = new BufferedReader(inputStreamReader);
String line = "";
while ((line = br.readLine()) != null) {
}
if (br != null) {
br.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (errorStream != null) {
errorStream.close();
}
} catch (NullPointerException e) {
e.printStackTrace();
}
} else if (OsSelect.isLinux()) {
//todo linux的ffmpeg使用
}
}
public static class PLAYBACK_NEWLINK_CB implements HCISUPStream.PLAYBACK_NEWLINK_CB {
@Override
public boolean invoke(int lPlayBackLinkHandle, HCISUPStream.NET_EHOME_PLAYBACK_NEWLINK_CB_INFO pNewLinkCBInfo, Pointer pUserData) {
pNewLinkCBInfo.read();
log.info("PLAYBACK_NEWLINK_CB callback, szDeviceID:" + new String(pNewLinkCBInfo.szDeviceID).trim()
+ ",lSessionID:" + pNewLinkCBInfo.lSessionID + ",dwChannelNo:" + pNewLinkCBInfo.dwChannelNo);
m_lPlayBackLinkHandle = lPlayBackLinkHandle;
HCISUPStream.NET_EHOME_PLAYBACK_DATA_CB_PARAM struCBParam = new HCISUPStream.NET_EHOME_PLAYBACK_DATA_CB_PARAM();
//預(yù)覽數(shù)據(jù)回調(diào)參數(shù)
if (fPLAYBACK_DATA_CB == null) {
fPLAYBACK_DATA_CB = new PLAYBACK_DATA_CB();
}
// pNewLinkCBInfo.fnPlayBackDataCB = fPLAYBACK_DATA_CB;
// pNewLinkCBInfo.byStreamFormat = 0;
struCBParam.fnPlayBackDataCB = fPLAYBACK_DATA_CB;
struCBParam.byStreamFormat = 0;
struCBParam.write();
// pNewLinkCBInfo.write();
if (!hCEhomeStream.NET_ESTREAM_SetPlayBackDataCB(lPlayBackLinkHandle, struCBParam)) {
log.info("NET_ESTREAM_SetPlayBackDataCB failed");
}
return true;
}
}
public static class PLAYBACK_DATA_CB implements HCISUPStream.PLAYBACK_DATA_CB {
//實(shí)時流回調(diào)函數(shù)
@Override
public boolean invoke(int iPlayBackLinkHandle, HCISUPStream.NET_EHOME_PLAYBACK_DATA_CB_INFO pDataCBInfo, Pointer pUserData) {
if (iCount == 500) {//降低打印頻率
log.info("PLAYBACK_DATA_CB callback , dwDataLen:" + pDataCBInfo.dwDataLen + ",dwType:" + pDataCBInfo.dwType);
iCount = 0;
}
iCount++;
//播放庫SDK解碼顯示在win窗口上,
switch (pDataCBInfo.dwType) {
case HCNetSDK.NET_DVR_SYSHEAD: //系統(tǒng)頭
// boolean b_port = playCtrl.PlayM4_GetPort(m_lPort);
// if (b_port == false) //獲取播放庫未使用的通道號
// {
// break;
// }
// if (pDataCBInfo.dwDataLen > 0) {
// if (!playCtrl.PlayM4_SetOverlayMode(m_lPort.getValue(), false, 0)) {
// break;
// }
//
// if (!playCtrl.PlayM4_SetStreamOpenMode(m_lPort.getValue(), PlayCtrl.STREAME_FILE)) //設(shè)置文件流播放模式
// {
// break;
// }
//
// if (!playCtrl.PlayM4_OpenStream(m_lPort.getValue(), pDataCBInfo.pData, pDataCBInfo.dwDataLen, 2 * 1024 * 1024)) //打開流接口
// {
// break;
// }
// W32API.HWND hwnd = new W32API.HWND(Native.getComponentPointer(IsupTest.panelRealplay));
// if (!playCtrl.PlayM4_Play(m_lPort.getValue(), hwnd)) //播放開始
// {
// break;
// }
// }
case HCNetSDK.NET_DVR_STREAMDATA: //碼流數(shù)據(jù)
if (pDataCBInfo.dwDataLen > 0) {
// for (int i = 0; i < 1000; i++) {
// boolean bRet = playCtrl.PlayM4_InputData(m_lPort.getValue(), pDataCBInfo.pData, pDataCBInfo.dwDataLen);
// if (!bRet) {
// if (i >= 999) {
// log.info("PlayM4_InputData,failed err:" + playCtrl.PlayM4_GetLastError(m_lPort.getValue()));
// }
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// } else {
// break;
// }
// }
try {
String fileName = redisUtil.get("downloadHandle:" + iPlayBackLinkHandle);
FileOutputStream m_file = new FileOutputStream(fileName, true);
long offset = 0;
ByteBuffer buffers = pDataCBInfo.pData.getByteBuffer(offset, pDataCBInfo.dwDataLen);
byte[] bytes = new byte[pDataCBInfo.dwDataLen];
buffers.rewind();
buffers.get(bytes);
m_file.write(bytes);
m_file.close();
// if (pDataCBInfo.dwDataLen < 1024)
// VideoUtil.convetor(fileName, fileName + ".mp4");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
break;
//如果僅需保存回放的視頻流文件,參考一下注釋的代碼
/*try {
m_file = new FileOutputStream(file, true);
long offset = 0;
ByteBuffer buffers = pDataCBInfo.pData.getByteBuffer(offset, pDataCBInfo.dwDataLen);
byte [] bytes = new byte[pDataCBInfo.dwDataLen];
buffers.rewind();
buffers.get(bytes);
m_file.write(bytes);
m_file.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
case 3: //結(jié)束
String fileName = redisUtil.get("downloadHandle:" + iPlayBackLinkHandle);
try {
if (OsSelect.isLinux()) {
convetorLinux(fileName, fileName + ".mp4");
} else {
convetorWindows(fileName, fileName + ".mp4");
}
break;
}catch (Exception ex) {
ex.printStackTrace();
}
}
return true;
}
}
public static void convetorWindows(String videoInputPath, String videoOutPath) throws Exception{
String ffmpegExe = "E:\\software\\ffmpeg-5.0.1-essentials_build\\bin\\ffmpeg.exe";
List<String> command = new ArrayList<>();
command.add(ffmpegExe);
command.add("-i");
command.add(videoInputPath);
command.add("-c");
command.add("copy");
command.add("-an");
command.add(videoOutPath);
ProcessBuilder builder = new ProcessBuilder(command);
Process process = null;
try {
process = builder.start();
} catch (IOException e) {
e.printStackTrace();
}
// 使用這種方式會在瞬間大量消耗CPU和內(nèi)存等系統(tǒng)資源,所以這里我們需要對流進(jìn)行處理
try {
InputStream errorStream = process.getErrorStream();
InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
BufferedReader br = new BufferedReader(inputStreamReader);
String line = "";
while ((line = br.readLine()) != null) {
}
if (br != null) {
br.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (errorStream != null) {
errorStream.close();
}
Path p = Paths.get(videoInputPath);
Files.delete(p);
} catch (NullPointerException e) {
e.printStackTrace();
}
}
public static void convetorLinux(String videoInputPath, String videoOutPath) throws Exception {
String ffmpegExe = "/usr/local/ffmpeg/bin/ffmpeg";
String videoCommend = ffmpegExe + " -i " + videoInputPath + " -c copy -an " + videoOutPath;
try {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(videoCommend);
InputStream stderr = proc.getErrorStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null){
}
if (br != null) {
br.close();
}
if (isr != null) {
isr.close();
}
if (stderr != null) {
stderr.close();
}
int exitVal = proc.waitFor();
Path p = Paths.get(videoInputPath);
Files.delete(p);
} catch (Throwable t) {
t.printStackTrace();
}
}
}
到了這里,關(guān)于web實(shí)時預(yù)覽功能開發(fā) java 海康sdk nvr的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!