1. 程式人生 > >Android平臺上整合大華SDK

Android平臺上整合大華SDK

在專案中需要接入大華裝置,因此我們集成了大華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;
}
}