在项目中需要接入海康设备,因此我们集成了海康Android版本SDK。它分为Device Network SDK和Player SDK。前者用于设备连接、网络通信;后者用于解码、播放。
在APP中,关于海康设备,我们实现了以下功能:添加设备、获取通道、实时预览、远程回放。
接下来我们一个一个来分析如何实现:
首先,登录设备,用到的是这个方法:HCNetSDK.getInstance().NET_DVR_Login_V30(String sDvrIp, int iDvrPort, String sUsername, String sPassword, NET_DVR_DEVICEINFO_V30 deviceInfo)
具体代码实现如下:
HCNetSDK.getInstance().NET_DVR_Init(); //初始化SDKNET_DVR_DEVICEINFO_V30 m_oNetDvrDeviceInfoV30 = new NET_DVR_DEVICEINFO_V30();if (null == m_oNetDvrDeviceInfoV30) { Log.e("Hikvision", "HKNetDvrDeviceInfoV30 new is failed!"); Message msg = Message.obtain(); msg.what = 1; if (!AddDeviceActivity.this.isFinishing()) { msg.obj = getResources().getString(R.string.loginFailed); } handler.sendMessage(msg); return;}int iLogID = HCNetSDK.getInstance().NET_DVR_Login_V30(ipAddress, port, userName, password, m_oNetDvrDeviceInfoV30); //登录设备
接着,获取通道,
如果iLogID不小于0,则登录成功。
获取开始通道号、通道个数,代码如下:
一般情况时,
if(m_oNetDvrDeviceInfoV30.byChanNum > 0) { m_iStartChan = m_oNetDvrDeviceInfoV30.byStartChan; m_iChanNum = m_oNetDvrDeviceInfoV30.byChanNum; } else if(m_oNetDvrDeviceInfoV30.byIPChanNum > 0) { m_iStartChan = m_oNetDvrDeviceInfoV30.byStartDChan; m_iChanNum = m_oNetDvrDeviceInfoV30.byIPChanNum + m_oNetDvrDeviceInfoV30.byHighDChanNum * 256; }
复杂情况时(比如模拟通道和数字通道混合、所获取的通道并不都是valid可用的等)
NET_DVR_IPPARACFG_V40 net_dvr_ipparacfg_v40 = new NET_DVR_IPPARACFG_V40(); //IP Device Resource and IP Channel Resource Configuration HCNetSDK.getInstance().NET_DVR_GetDVRConfig(iLogID, HCNetSDK.NET_DVR_GET_IPPARACFG_V40, 0, net_dvr_ipparacfg_v40); //Get Device Settings Information Log.i("Hik_An_CHANNEL_NUM", net_dvr_ipparacfg_v40.dwAChanNum + ""); Log.i("Hik_Di_CHANNEL_NUM", net_dvr_ipparacfg_v40.dwDChanNum + ""); NET_DVR_DIGITAL_CHANNEL_STATE net_dvr_digital_channel_state = new NET_DVR_DIGITAL_CHANNEL_STATE(); //Channel Status HCNetSDK.getInstance().NET_DVR_GetDVRConfig(iLogID, HCNetSDK.NET_DVR_GET_DIGITAL_CHANNEL_STATE, 0xFFFFFFFF, net_dvr_digital_channel_state); byte[] byAnalogChanState = net_dvr_digital_channel_state.byAnalogChanState; byte[] byDigitalChanState = net_dvr_digital_channel_state.byDigitalChanState; SQLiteDatabase db = mySqliteHelper.getWritableDatabase(); for (int i = 0; i < net_dvr_ipparacfg_v40.dwAChanNum; i++) { if (byAnalogChanState[i] == 1) mCount ++; } for (int i = 0; i < net_dvr_ipparacfg_v40.dwDChanNum; i++) { if (byDigitalChanState[i] == 1) mCount ++; } Log.i("Hik_VALID_CHANNEL_NUM", mCount + ""); for (int i = 0; i < net_dvr_ipparacfg_v40.dwAChanNum; i++) { if (byAnalogChanState[i] == 1) DbManger.execDataSql(db, "insert into " + Dbutils.TABLE_NAME + "(" + Dbutils.CAMERA_NAME + "," + Dbutils.CAMERA_ID + "," + Dbutils.SITE_NAME + "," + Dbutils.DEVICE_NAME + "," + Dbutils.ADDRESS + "," + Dbutils.TCP + "," + Dbutils.USERNAME + "," + Dbutils.PASSWORD + "," + Dbutils.CAMERA_NUM + "," + Dbutils.DEVICE_TYPE + ") values('" + "HikCAM " + (i + 1) + "'," + (m_oNetDvrDeviceInfoV30.byStartChan + i) + ",'" + site_name + "','" + device_name + "','" + ipAddress + "'," + port + ",'" + userName + "','" + password + "'," + mCount + ",'" + "Hikvision Device" + "')"); } for (int i = 0; i < net_dvr_ipparacfg_v40.dwDChanNum; i++) { if (byDigitalChanState[i] == 1) DbManger.execDataSql(db, "insert into " + Dbutils.TABLE_NAME + "(" + Dbutils.CAMERA_NAME + "," + Dbutils.CAMERA_ID + "," + Dbutils.SITE_NAME + "," + Dbutils.DEVICE_NAME + "," + Dbutils.ADDRESS + "," + Dbutils.TCP + "," + Dbutils.USERNAME + "," + Dbutils.PASSWORD + "," + Dbutils.CAMERA_NUM + "," + Dbutils.DEVICE_TYPE + ") values('" + "HikCAM " + (i + 1) + "'," + (net_dvr_ipparacfg_v40.dwStartDChan + i) + ",'" + site_name + "','" + device_name + "','" + ipAddress + "'," + port + ",'" + userName + "','" + password + "'," + mCount + ",'" + "Hikvision Device" + "')"); } //以下处理是针对net_dvr_ipparacfg_v40.dwAChanNum和net_dvr_ipparacfg_v40.dwDChanNum均为0,但是仍然有通道的海康设备 if (net_dvr_ipparacfg_v40.dwAChanNum == 0 && net_dvr_ipparacfg_v40.dwDChanNum == 0) { if(m_oNetDvrDeviceInfoV30.byChanNum > 0) { m_iStartChan = m_oNetDvrDeviceInfoV30.byStartChan; m_iChanNum = m_oNetDvrDeviceInfoV30.byChanNum; } else if(m_oNetDvrDeviceInfoV30.byIPChanNum > 0) { m_iStartChan = m_oNetDvrDeviceInfoV30.byStartDChan; m_iChanNum = m_oNetDvrDeviceInfoV30.byIPChanNum + m_oNetDvrDeviceInfoV30.byHighDChanNum * 256; } mCount = m_iChanNum; for (int i = 0 ; i < m_iChanNum ; i ++) { int cameraId = m_iStartChan + i; DbManger.execDataSql(db, "insert into " + Dbutils.TABLE_NAME + "(" + Dbutils.CAMERA_NAME + "," + Dbutils.CAMERA_ID + "," + Dbutils.SITE_NAME + "," + Dbutils.DEVICE_NAME + "," + Dbutils.ADDRESS + "," + Dbutils.TCP + "," + Dbutils.USERNAME + "," + Dbutils.PASSWORD + "," + Dbutils.CAMERA_NUM + "," + Dbutils.DEVICE_TYPE + ") values('" + "HikCAM " + (i + 1) + "'," + cameraId + ",'" + site_name + "','" + device_name + "','" + ipAddress + "'," + port + ",'" + userName + "','" + password + "'," + mCount + ",'" + "Hikvision Device" + "')"); } }
对海康摄像头进行实时预览:用到的方法是HCNetSDK.getInstance().NET_DVR_RealPlay_V40(int var1, NET_DVR_PREVIEWINFO var2, RealPlayCallBack var3)
具体实现代码如下:
用之前登录成功返回的iLogID和之前获取的通道号
NET_DVR_PREVIEWINFO previewInfo = new NET_DVR_PREVIEWINFO(); previewInfo.lChannel = channelNo; //通道号 previewInfo.dwStreamType = streamType; //码流类型 previewInfo.bBlocked = 1;
RealPlayCallBack fRealDataCallBack = getRealPlayerCbf();
int m_iPlayID = HCNetSDK.getInstance().NET_DVR_RealPlay_V40(iLogID, previewInfo, fRealDataCallBack);
private RealPlayCallBack getRealPlayerCbf() { RealPlayCallBack cbf = new RealPlayCallBack() { public void fRealDataCallBack(int iRealHandle, int iDataType, byte[] pDataBuffer, int iDataSize) { processRealData(1, iDataType, pDataBuffer, iDataSize, Player.STREAM_REALTIME); } }; return cbf; } private void processRealData(int iPlayViewNo, int iDataType, byte[] pDataBuffer, int iDataSize, int iStreamMode) { if (m_bNeedDecode) { if (HCNetSDK.NET_DVR_SYSHEAD == iDataType) { m_iPort = Player.getInstance().getPort(); if (m_iPort == -1) { Log.e(TAG_ERROR, "getPort is failed with: " + Player.getInstance().getLastError(m_iPort)); return; } Log.i(TAG, "getPort success with: " + m_iPort); if (iDataSize > 0) { if (!Player.getInstance().setStreamOpenMode(m_iPort, iStreamMode)) //set stream mode { Log.e(TAG_ERROR, "setStreamOpenMode failed"); return; } if (!Player.getInstance().openStream(m_iPort, pDataBuffer, iDataSize, 2 * 1024 * 1024)) //open stream { Log.e(TAG_ERROR, "openStream failed"); return; } if (!Player.getInstance().play(m_iPort, surfaceView.getHolder())) { Log.e(TAG_ERROR, "play failed"); return; } if (!Player.getInstance().playSound(m_iPort)) { Log.e(TAG_ERROR, "playSound failed with error code:" + Player.getInstance().getLastError(m_iPort)); return; } } } else { if (!Player.getInstance().inputData(m_iPort, pDataBuffer, iDataSize)) { for (int i = 0; i < 4000 && m_iPlaybackID >= 0 && !m_bStopPlayback; i++) { if (Player.getInstance().inputData(m_iPort, pDataBuffer, iDataSize)) { break; } if (i % 100 == 0) { Log.e(TAG_ERROR, "inputData failed with: " + Player.getInstance().getLastError(m_iPort) + ", i:" + i); } try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } }如果返回的m_iPlayID不小于0,则实时预览成功,于是可以看到海康摄像头的实时视频。
停止实时预览,具体实现代码如下:
/** * 停止实时预览 * @param playId * @param port */ public void stopLive(int playId, int port) { if (playId >= 0) { if (HCNetSDK.getInstance().NET_DVR_StopRealPlay(playId)) { Player.getInstance().stopSound(); if (Player.getInstance().stop(port)) { if (Player.getInstance().closeStream(port)) { if (Player.getInstance().freePort(port)) { Log.i(TAG, "close success"); } else { Log.e(TAG_ERROR, "freePort is failed!" + port); } } else { Log.e(TAG_ERROR, "closeStream is failed!"); } } else { Log.e(TAG_ERROR, "stop is failed!"); } } else { Log.e(TAG_ERROR, "StopRealPlay is failed!Err:" + HCNetSDK.getInstance().NET_DVR_GetLastError()); } } }
对海康摄像头进行录像回放,我们这里是采用按照时间进行回放,用到的方法是HCNetSDK.getInstance().NET_DVR_PlayBackByTime(int var1, int var2, NET_DVR_TIME var3, NET_DVR_TIME var4)
具体实现代码如下:
用之前登录成功返回的iLogID和之前获取的通道号
NET_DVR_TIME struBegin = new NET_DVR_TIME(); //开始时间 NET_DVR_TIME struEnd = new NET_DVR_TIME(); //结束时间 struBegin.dwYear = bgYear; struBegin.dwMonth = bgMonth; struBegin.dwDay = bgDay; struBegin.dwHour = bgHour; struBegin.dwMinute = bgMinute; struBegin.dwSecond = bgSecond; struEnd.dwYear = endYear; struEnd.dwMonth = endMonth; struEnd.dwDay = endDay; struEnd.dwHour = endHour; struEnd.dwMinute = endMinute; struEnd.dwSecond = endSecond;
PlaybackCallBack fPlaybackCallBack = getPlayerbackPlayerCbf();
private PlaybackCallBack getPlayerbackPlayerCbf() { PlaybackCallBack cbf = new PlaybackCallBack() { @Override public void fPlayDataCallBack(int iPlaybackHandle, int iDataType, byte[] pDataBuffer, int iDataSize) { processRealData(1, iDataType, pDataBuffer, iDataSize, Player.STREAM_FILE); } }; return cbf; } public void processRealData(int iPlayViewNo, int iDataType, byte[] pDataBuffer, int iDataSize, int iStreamMode) { if(m_bNeedDecode) { if(HCNetSDK.NET_DVR_SYSHEAD == iDataType) { /*if(m_iPort >= 0) { return; }*/ m_iPort = Player.getInstance().getPort(); if(m_iPort == -1) { Log.e(TAG, "Hikvision getPort is failed with: " + Player.getInstance().getLastError(m_iPort)); return; } Log.i(TAG, "Hikvision getPort succ with: " + m_iPort); if (iDataSize > 0) { if (!Player.getInstance().setStreamOpenMode(m_iPort, iStreamMode)) { //set stream mode Log.e(TAG, "Hikvision setStreamOpenMode failed"); return; } if (!Player.getInstance().openStream(m_iPort, pDataBuffer, iDataSize, 2*1024*1024)) { //open stream Log.e(TAG, "Hikvision openStream failed"); return; } if (!Player.getInstance().play(m_iPort, surfaceView.getHolder())) { Log.e(TAG, "Hikvision play failed"); return; } if(!Player.getInstance().playSound(m_iPort)) { Log.e(TAG, "Hikvision playSound failed with error code:" + Player.getInstance().getLastError(m_iPort)); return; } } } else { if (!Player.getInstance().inputData(m_iPort, pDataBuffer, iDataSize)) { // Log.e(TAG, "inputData failed with: " + Player.getInstance().getLastError(m_iPort)); for(int i = 0; i < 4000 && m_iPlaybackID >=0 && !m_bStopPlayback; i++) { if (Player.getInstance().inputData(m_iPort, pDataBuffer, iDataSize)) { break; } if(i % 100 == 0) { Log.e(TAG, "Hikvision inputData failed with: " + Player.getInstance().getLastError(m_iPort) + ", i:" + i); } try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } }
int m_iPlaybackID = HCNetSDK.getInstance().NET_DVR_PlayBackByTime(iLogID, channelNo, struBegin, struEnd);
if(m_iPlaybackID >= 0) { if(!HCNetSDK.getInstance().NET_DVR_SetPlayDataCallBack(m_iPlaybackID, fPlaybackCallBack)) { Log.e(TAG, "Hikvision set playback callback failed!"); Message msg = Message.obtain(); msg.what = 1; if (!PlaybackActivity.this.isFinishing()) { msg.obj = getResources().getString(R.string.fail_start_playback); } handler.sendMessage(msg); return ; } NET_DVR_PLAYBACK_INFO struPlaybackInfo = null ; if(!HCNetSDK.getInstance().NET_DVR_PlayBackControl_V40(m_iPlaybackID, PlaybackControlCommand.NET_DVR_PLAYSTART, null, 0, struPlaybackInfo)) { Log.e(TAG, "Hikvision net sdk playback start failed!"); Message msg = Message.obtain(); msg.what = 1; if (!PlaybackActivity.this.isFinishing()) { msg.obj = getResources().getString(R.string.fail_start_playback); } handler.sendMessage(msg); return ; } m_bStopPlayback = false; loadFinish = true; Message msg = Message.obtain(); msg.what = 2; handler.sendMessage(msg); Thread thread = new Thread() { public void run() { int nProgress = -1; while(true) { nProgress = HCNetSDK.getInstance().NET_DVR_GetPlayBackPos(m_iPlaybackID); if(nProgress < 0 || nProgress >= 100) { break; } try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; thread.start(); } else { Log.e(TAG, "Hikvision NET_DVR_PlayBackByTime failed, error code: " + HCNetSDK.getInstance().NET_DVR_GetLastError()); }
停止回放,具体实现代码如下:
public void stopPlaybackHikvision() { m_bStopPlayback = true; if(!HCNetSDK.getInstance().NET_DVR_StopPlayBack(m_iPlaybackID)) { Log.e(TAG, "Hikvision net sdk stop playback failed"); } stopSinglePlayer(); Log.i(TAG, "Hikvision close success"); } private void stopSinglePlayer() { Player.getInstance().stopSound(); // player stop play if (!Player.getInstance().stop(m_iPort)) { Log.e(TAG, "Hikvision stop is failed!"); return; } if(!Player.getInstance().closeStream(m_iPort)) { Log.e(TAG, "Hikvision closeStream is failed!"); return; } if(!Player.getInstance().freePort(m_iPort)) { Log.e(TAG, "Hikvision freePort is failed!" + m_iPort); return; } m_iPort = -1; }