Android平臺上整合大華SDK
阿新 • • 發佈:2019-01-23
在專案中需要接入大華裝置,因此我們集成了大華Android版本SDK。與海康SDK類似,它也是分為NetSDK和PlaySDK。
前者用於裝置連線、網路通訊;後者用於解碼、播放。
在APP中,關於大華裝置,我們實現了以下功能:新增裝置、獲取通道、實時預覽、遠端回放。
接下來,我們一個一個來分析如何實現。
首先,登入裝置,用到的方法是INetSDK.LoginEx(String pchDVRIP, int wDVRPort, String pchUserName, String pchPassword, int nSpecCap, Object pCapParam, NET_DEVICEINFO lpDeviceInfo, Integer nError)
具體程式碼實現如下:
首先,我們需要做一些準備工作:
INetSDK.LoadLibrarys(); DeviceDisConnect disConnect = new DeviceDisConnect(); INetSDK.Init(disConnect); //初始化SDK,在所有的SDK函式之前呼叫 /** * 設定連線裝置超時時間和嘗試次數 * @param nWaitTime 客戶端與裝置的連線等待時間,毫秒級 * @param nTryTimes 連線次數 */ INetSDK.SetConnectTime(4000, 2); NET_PARAM stNetParam = new NET_PARAM();//NET_PARAM 該類用於設定登入時的相關引數 stNetParam.nWaittime = 10000; //等待超時時間(毫秒為單位) stNetParam.nSearchRecordTime = 10000; //按時間查詢錄影檔案的超時時間(毫秒為單位) INetSDK.SetNetworkParam(stNetParam); //設定登陸網路環境 NET_DEVICEINFO deviceInfo = new NET_DEVICEINFO(); //裝置資訊 Integer error = new Integer(0); DeviceReConnect reConnect = new DeviceReConnect();INetSDK.SetAutoReconnect(reConnect); //設定斷線重連成功回撥函式,設定後SDK內部斷線自動重連 DeviceSubDisConnect subDisConnect = new DeviceSubDisConnect(); INetSDK.SetSubconnCallBack(subDisConnect); //設定動態子連線斷線回撥函式,目前SVR裝置的監視和回放是短連線的 INetSDK.SetDVRMessCallBack(new Test_CB_fMessageCallBack()); //設定訊息回撥函式
/** * 裝置未連線上 */ public class DeviceDisConnect implements CB_fDisConnect { @Override public void invoke(long lLoginID, String pchDVRIP, int nDVRPort) { return; } }
/** * 裝置連線恢復 */ public class DeviceReConnect implements CB_fHaveReConnect { @Override public void invoke(long lLoginID, String pchDVRIP, int nDVRPort) {} }
/** * 動態子連線斷開 */ public class DeviceSubDisConnect implements CB_fSubDisConnect { @Override public void invoke(int emInterfaceType, boolean bOnline, long lOperateHandle, long lLoginID) {} }
/** * 訊息回撥函式 */ class Test_CB_fMessageCallBack implements CB_fMessageCallBack { @Override public boolean invoke(int lCommand, long lLoginID, Object obj, String pchDVRIP, int nDVRPort) { if (12295 == lCommand) { DEV_PLAY_RESULT stResult = (DEV_PLAY_RESULT) obj; } return true; } }接下來,呼叫登入方法:
long loginHandle = INetSDK.LoginEx(ipAddress, port, userName, password, mSpecCap, null, deviceInfo, error);mSpecCap為裝置支援的能力,這裡值為20。
如果loginHandle的值不為0,那麼登入成功。
獲取通道
m_speedCtrl = false; m_schedule = 0; SDK_DEV_ENABLE_INFO stEnableInfo = new SDK_DEV_ENABLE_INFO(); if (INetSDK.QuerySystemInfo(loginHandle, SDK_SYS_ABILITY.ABILITY_DEVALL_INFO, stEnableInfo, 3000)) { if (stEnableInfo.IsFucEnable[SDK_DEV_FUNC.EN_PLAYBACK_SPEED_CTRL] != 0) { m_speedCtrl = true; } m_schedule = stEnableInfo.IsFucEnable[SDK_DEV_FUNC.EN_SCHEDULE]; } stCfgCapAlarm = new CFG_CAP_ALARM_INFO(); char szOutBuffer[] = new char[10240]; Integer stError = new Integer(0); boolean bQN = INetSDK.QueryNewSystemInfo(loginHandle, FinalVar.CFG_CAP_ALARM, 0, szOutBuffer, stError, 5000); if (bQN) { bQN = INetSDK.ParseData(FinalVar.CFG_CAP_ALARM, szOutBuffer, stCfgCapAlarm, null); //解析查詢到的配置資訊 if (!bQN) { Log.e("dahua", "INetSDK.ParseData CFG_CAP_ALARM error"); } } else { Log.e("dahua", "INetSDK.QueryNewSystemInfo CFG_CAP_ALARM error"); } mCount = deviceInfo.byChanNum; if (-1 == deviceInfo.byChanNum) { SDK_PRODUCTION_DEFNITION stDef = new SDK_PRODUCTION_DEFNITION(); boolean bRet = INetSDK.QueryProductionDefinition(loginHandle, stDef, 3000); if (bRet) { mCount = stDef.nVideoInChannel + stDef.nMaxRemoteInputChannels; } }最終得到的mCount就是通道數。
對大華攝像頭進行實時預覽,用到的方法是INetSDK.RealPlayEx(int lLoginID, int nChannelID, int rType)
用之前獲取的loginHandle,
long lRealHandle = INetSDK.RealPlayEx(loginHandle, channelNo, streamType);如果lRealHandle不為0,則成功,接下來:
mPort = IPlaySDK.PLAYGetFreePort();
boolean bOpenRet = IPlaySDK.PLAYOpenStream(mPort, null, 0, 1024 * 1024 * 2) == 0 ? false : true; if (bOpenRet) { boolean bPlayRet = IPlaySDK.PLAYPlay(mPort, surfaceView) == 0 ? false : true; if (bPlayRet) { boolean bSuccess = IPlaySDK.PLAYPlaySoundShare(mPort) == 0 ? false : true; /*if (!bSuccess) { IPlaySDK.PLAYStop(mPort); IPlaySDK.PLAYCloseStream(mPort); return false; } if (-1 == nCurVolume) { nCurVolume = IPlaySDK.PLAYGetVolume(mPort); } else { IPlaySDK.PLAYSetVolume(mPort, nCurVolume); }*/ } else {IPlaySDK.PLAYCloseStream(mPort); return false; } } else {//IPlaySDK.PLAYCloseStream(mPort); return false; } return true;如果最終return true,接下來,我們繼續:
public class TestRealDataCallBackEx implements CB_fRealDataCallBackEx { public int port; public TestRealDataCallBackEx(int port) { this.port = port; } /** * 網路斷線回撥函式 * @param lRealHandle 實時監視ID * @param dwDataType 回調出來的資料型別 * @param pBuffer 回撥資料,根據資料型別的不同每次回撥不同的長度的資料,除型別0,其他資料型別都是按幀,每次回撥一幀資料 * @param dwBufSize 回撥資料引數結構體,根據不同的型別,引數結構也不一致 * @param param 回撥資料的長度,根據不同的型別,長度也不同(單位位元組) */ @Override public void invoke(long lRealHandle, int dwDataType, byte[] pBuffer, int dwBufSize, int param) { if (dwDataType == 0) { IPlaySDK.PLAYInputData(port, pBuffer, pBuffer.length); } } }
public class TestVideoDataCallBack implements IPlaySDKCallBack.fDemuxCBFun { public FileOutputStream outputStream; public TestVideoDataCallBack(FileOutputStream outputStream) { this.outputStream = outputStream; } @Override public void invoke(int nPort, byte[] pOrgBuffer, int nOrgLen, byte[] pBuffer, int nLen, IPlaySDKCallBack.DEMUX_INFO stInfo, long dwUser) { try { if (null != outputStream) { outputStream.write(pBuffer); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
TestRealDataCallBackEx m_callbac = new TestRealDataCallBackEx(mPort); TestVideoDataCallBack m_VideoCallback = new TestVideoDataCallBack(m_Fout); if (lRealHandle != 0) { INetSDK.SetRealDataCallBackEx(lRealHandle, m_callbac, 1);}
停止實時預覽:
/** * 停止實時預覽 * @param port * @param lRealHandle */ public void stopLive(int port, long lRealHandle) { IPlaySDK.PLAYStop(port); IPlaySDK.PLAYStopSoundShare(port); IPlaySDK.PLAYCloseStream(port); INetSDK.StopRealPlayEx(lRealHandle); }
對大華攝像頭進行錄影回放,我們這裡是採用按照時間進行回放,用到的方法是INetSDK.PlayBackTimeEx(long lLoginID, int nChannelID, NET_TIME startTime, NET_TIME stopTime, CB_fDowmLoadPosCallBack posUser, CB_fDataCallBack dataUser)
具體實現程式碼如下:
先做一些準備工作:
NET_TIME stTimeStart = new NET_TIME(); NET_TIME stTimeEnd = new NET_TIME(); getPlaybackTime(stTimeStart, stTimeEnd, bgYear, bgMonth, bgDay, bgHour, bgMinute, bgSecond, endYear, endMonth, endDay, endHour, endMinute, endSecond);
public void getPlaybackTime(NET_TIME stTimeStart, NET_TIME stTimeEnd,int bgYear,int bgMonth,int bgDay,int bgHour,int bgMinute,int bgSecond, int endYear,int endMonth,int endDay,int endHour,int endMinute,int endSecond) { stTimeStart.dwYear = bgYear; stTimeStart.dwMonth = bgMonth; stTimeStart.dwDay = bgDay; stTimeStart.dwHour = bgHour; stTimeStart.dwMinute = bgMinute; stTimeStart.dwSecond = bgSecond; stTimeEnd.dwYear = endYear; stTimeEnd.dwMonth = endMonth; stTimeEnd.dwDay = endDay; stTimeEnd.dwHour = endHour; stTimeEnd.dwMinute = endMinute; stTimeEnd.dwSecond = endSecond; }
public class TestfDataCallBack implements CB_fDataCallBack { @Override public int invoke(long lPlaybackHandle, int dwDataType, byte buffer[], int dwBufferSize) { if (0 == dwDataType) { return IPlaySDK.PLAYInputData(nPort, buffer, buffer.length); } else if ( dwDataType == 2 ) { //m_PlayView.drawColor(pBuffer); } else if ( dwDataType == 3 ) { //m_PlayView.drawColor(pBuffer); } return 0; } }
public class TestDownLoadPosCallBack implements CB_fDownLoadPosCallBack { @Override public void invoke(long lPlayHandle, int dwTotalSize, int dwDownLoadSize) { Log.i("playback",dwTotalSize+""); if (-1 == dwDownLoadSize) { //m_sbPbByTime.setProgress(dwTotalSize); new Thread(new Runnable() { @Override public void run() { if (0 != lPlaybackHandle) { stopPlayBackDahua(); } } }).start(); } else { //m_sbPbByTime.setProgress(dwDownLoadSize); } } }
TestfDataCallBack m_callback = new TestfDataCallBack(); TestDownLoadPosCallBack posUser = new TestDownLoadPosCallBack();
long lPlaybackHandle = INetSDK.PlayBackByTimeEx(loginHandle, channelNo, stTimeStart,
stTimeEnd, posUser, m_callback);
如果lPlaybackHandle不為0,則繼續:
IPlaySDK.PLAYSetPlayedTimeEx(nPort, 0); IPlaySDK.PLAYResetBuffer(nPort, 1); //清碼流分析庫 IPlaySDK.PLAYResetBuffer(nPort, 3); //清播放佇列 boolean bOpenRet = IPlaySDK.PLAYOpenStream(nPort, null, 0, 1024*1024*2) == 0 ? false : true; IPlaySDK.PLAYSetStreamOpenMode(nPort, Constants.STREAME_FILE); if (bOpenRet) { boolean bPlayRet = IPlaySDK.PLAYPlay(nPort, surfaceView) == 0 ? false : true; if (bPlayRet) { boolean bSuccess = IPlaySDK.PLAYPlaySoundShare(nPort) == 0 ? false : true; /*if(!bSuccess) { IPlaySDK.PLAYStop(nPort); IPlaySDK.PLAYCloseStream(nPort); Message msg = Message.obtain(); msg.what = 1; msg.obj = "Failed to start playback"; handler.sendMessage(msg); return; } else { }*/ loadFinish = true; Message msg = Message.obtain(); msg.what = 2; handler.sendMessage(msg); } else { IPlaySDK.PLAYCloseStream(nPort); return; } } else { return; }
停止回放:
public void stopPlayBackDahua() { if (lPlaybackHandle != 0) { IPlaySDK.PLAYStop(nPort); IPlaySDK.PLAYCloseStream(nPort); //在PLAYStop之後呼叫 INetSDK.StopPlayBack(lPlaybackHandle); lPlaybackHandle = 0; } }