一业崖、NET_DVR_SaveRealData方法
使用下面方法可以實(shí)現(xiàn)視頻錄像功能野芒。
private HCNetSDK sdk = HCNetSDK.INSTANCE;
sdk.NET_DVR_SaveRealData_V30(cameraInfo.getKey(), file.getPath() + "/" + fileName + ".mp4")
該方法有個(gè)問題,視頻可以錄制双炕,但是不能被前端頁面直接加載播放狞悲,因?yàn)橐曨l編碼格式問題,雖然可以用FFMPEG工具進(jìn)行格式轉(zhuǎn)化妇斤,但是引入第三方的庫(kù)摇锋,無疑會(huì)使代碼的維護(hù)性降低。
FFMPEG工具 地址 提取碼 zc14
使用FFmpeg進(jìn)行轉(zhuǎn)換的方法如下:
ffmpeg -i in.mp4 out.mp4
該方法網(wǎng)絡(luò)上有大量的帖子趟济,我直接放連接過來乱投,可以自行前往學(xué)習(xí)
大牛博客地址
二、NET_DVR_SaveRealData_V30方法
這個(gè)方法是問呵瓯啵康的工程師得到的,跟航P蹋康的工程師交流還是挺美好的媳纬,工程師很耐心,直到自己的問題得到解答施掏,代碼測(cè)試通過钮惠,所以還是必須給點(diǎn)個(gè)贊。
附上該方法的SDK文檔
按照SDK文檔的說明七芭,第二個(gè)參數(shù)傳2素挽,就可以了
//預(yù)覽成功后 調(diào)用接口使視頻資源保存到文件中
if (!sdk.NET_DVR_SaveRealData_V30(cameraInfo.getKey(), 2,file.getPath() + "/" + fileName + ".mp4")) {
log.error("保存視頻文件到文件夾失敗 錯(cuò)誤碼為: " + sdk.NET_DVR_GetLastError());
logoutHIK(cameraInfo);
return;
}
到這里會(huì)發(fā)現(xiàn)一個(gè)問題,官方下載的SDK HCNetSDK.java文件中沒有NET_DVR_SaveRealData_V30這個(gè)方法狸驳,尷尬了预明。
這就是官方SDK的坑點(diǎn),SDK中有耙箍,但是HCNetSDK.java文件中沒有撰糠,好多同學(xué)可能都會(huì)懵一下,這里可以將SDK中的方法直接復(fù)制進(jìn)HCNetSDK.java文件即可辩昆。SDK是按照C語言來描述的阅酪,JAVA要做響應(yīng)的適配改變。
boolean NET_DVR_SaveRealData_V30(NativeLong lRealHandle,int STREAM_TYPE,String sFileName);
OK,到此視頻已經(jīng)可以存儲(chǔ)术辐,播放也正常砚尽,但是你又會(huì)發(fā)現(xiàn)一個(gè)新的問題,就是保存的視頻辉词,設(shè)定1分鐘必孤,但是只有51秒 ,52秒较屿,57秒等隧魄,就是沒有1分鐘的,甚至59秒的都很少隘蝎,如果要求不那么高還好购啄,到這里就可以結(jié)束了,如果要求的高嘱么,那就得做出處理了狮含。
三、強(qiáng)制I幀
這里面其實(shí)是有一個(gè) I幀的定義 的
錄像數(shù)據(jù)解碼播放必須從I幀開始曼振,而客戶端錄像的時(shí)候開始時(shí)間點(diǎn)不一定是I幀几迄,比如幀率25fps、I幀間隔100幀的情況下冰评,每4秒才一個(gè)I幀映胁,錄像播放可能存在1~4秒的延時(shí),所以錄像的時(shí)候可以強(qiáng)制設(shè)備生成一個(gè)I幀甲雅。
NET_DVR_MakeKeyFrame強(qiáng)制主碼流生成一個(gè)I幀解孙,NET_DVR_MakeKeyFrameSub強(qiáng)制子碼流生成一個(gè)I幀,z這兩個(gè)是老的接口抛人。
后來因?yàn)樵O(shè)備不只有主碼流和子碼流弛姜,還有三碼流、虛擬碼流等妖枚,因此增加了NET_DVR_RemoteControl(命令:NET_DVR_MAKE_I_FRAME)接口廷臼,兼容前面的兩個(gè)接口,輸入?yún)?shù)NET_DVR_I_FRAME中byStreamType表示碼流類型绝页。建議使用該接口荠商。
可以看到,如果I幀沒有到抒寂,也是不錄視頻的结啼,但是I幀一般會(huì)慢幾秒中,所以視頻長(zhǎng)度不夠自己配置的長(zhǎng)度
需要用到NET_DVR_RemoteControl 這個(gè)方法屈芜,會(huì)發(fā)現(xiàn) HCNetSDK.java文件中并沒有NET_DVR_RemoteControl 這個(gè)方法郊愧,繼續(xù)添加上朴译。
附上NET_DVR_RemoteControl 的SDK同樣,在 HCNetSDK.java文件中增加這個(gè)方法(根據(jù)java做了語法轉(zhuǎn)換属铁,如果不好轉(zhuǎn)眠寿,請(qǐng)參考原HCNetSDK.java文件中的數(shù)據(jù)類型)
boolean NET_DVR_RemoteControl(NativeLong lUserID, int dwCommand, Pointer pointer, int dwInBufferSize);
官方SDK簡(jiǎn)直了,有些方法沒有焦蘑,就連結(jié)構(gòu)體也沒有盯拱,都需要自己新增,沒辦法例嘱,誰讓咱要用人家的產(chǎn)品么
lpInBuffer參數(shù)對(duì)應(yīng)結(jié)構(gòu)體 NET_DVR_I_FRAME
看SDK手冊(cè) NET_DVR_I_FRAME 結(jié)構(gòu)體的官方文檔
//強(qiáng)制I幀參數(shù)結(jié)構(gòu)體狡逢。
public static class NET_DVR_I_FRAME extends Structure{
public int dwSize;
public byte[] sStreamID = new byte[32]; //流IDs SDK 中對(duì) STREAM_ID_LEN進(jìn)行了定義,賦值32
public int dwChannel;//通道號(hào)
public byte byStreamType; //碼流類型:0-主碼流拼卵,1-子碼流奢浑,2-碼流3,3-虛擬碼流腋腮,以此類推
public byte[] byRes = new byte[63]; //保留雀彼,置為0 按照SDK要求進(jìn)行對(duì)應(yīng)賦值
}
//新建結(jié)構(gòu)體對(duì)象
HCNetSDK.NET_DVR_I_FRAME netDvrIFrame = new HCNetSDK.NET_DVR_I_FRAME(); //新建結(jié)構(gòu)體對(duì)象
netDvrIFrame.read();
netDvrIFrame.dwChannel = 1; //因?yàn)樯衔拇a中設(shè)置了通道號(hào),按照上文中的設(shè)置
netDvrIFrame.byStreamType = 0;
netDvrIFrame.dwSize = netDvrIFrame.size();
netDvrIFrame.write();
if(!sdk.NET_DVR_RemoteControl(cameraInfo.getUserId(),3402,netDvrIFrame.getPointer(),netDvrIFrame.dwSize)){
log.error("強(qiáng)制I幀 錯(cuò)誤碼為: " + sdk.NET_DVR_GetLastError());
}
在每次錄像之前即寡,對(duì)I幀進(jìn)行強(qiáng)制設(shè)置徊哑,可以及時(shí)錄像,經(jīng)過測(cè)試基本上按照配置的時(shí)間進(jìn)行錄制聪富,比如1分鐘就是1分鐘莺丑,偶爾有59秒的情況,提到的問題已經(jīng)大大的修復(fù)了墩蔓。經(jīng)次一輪窒盐,對(duì)SDK的使用也有了更深的了解。自己踩過的坑钢拧,也記錄下來,也讓別人能很好的使用官方的SDK炕横。
最后附上程序源内,歡迎下載傳閱,另外還有悍莸睿康工程師給的有更全結(jié)構(gòu)體的HCNetSDK.java文件
百度網(wǎng)盤 鏈接:https://pan.baidu.com/s/1JEKvEnb5wTDtmNqlNsKvLg
提取碼:x4bj