在接触海康之前有接触过大华视频的集成,萤石视频的集成,现在海康8800的视频是第一次集成,其中遇到了一个坑还是值得说一下的(个人认为还是很坑的)。
下载地址:海康8800所需jar 和so文件
Demo地址:海康视频AndroidDemo
海康8800的视频集成步骤如下:
1、导入jar和so文件 (如果自己没有的话,文章开头有下载链接)
在build.gradle 中配置如下代码:
repositories { flatDir { dirs 'libs' } }
2、在Application中注册,代码如下:
OkHttpUtils.init(this);
MCRSDK.init();
RtspClient.initLib();
MCRSDK.setPrint(1, null);
}
- 你要有视频服务器的IP地址和端口,还需要登录视频平台的用户名和密码,这里我就不贴出公司的账号了,不然吃不了兜着走了:)。
4.根据3 的IP和端口获取分支
/*
* 获取分支线
*/
private void getFetchLine() {
new Thread() {
@Override
public void run() {
super.run();
List<LineInfo> lineInfoList = new ArrayList<>();
boolean ret = VMSNetSDK.getInstance().getLineList(SERVER_URL, lineInfoList);
if (ret) {
Message message = new Message();
message.what = AppConfig.Login.GET_LINE_SUCCESS;
message.obj = lineInfoList;
handler.sendMessage(message);
} else {
handler.sendEmptyMessage(AppConfig.Login.GET_LINE_FAILED);
}
}
}.start();
}
获取分之,需要在子线程中获取, 声明一个LineInfo 集合对象,用来存放获取到的分之,通过如下代码获取分之VMSNetSDK.getInstance().getLineList(SERVER_URL, lineInfoList);
该方法返回值是一个boolean类型,获取到分之返回true否则返回false, getLineList有两个参数,第一个是服务器地址,格式如下http://xxx.xxx.xxx.xxx:端口
,第二个参数是获取到分支的集合。
z这里我用handler 处理几种状态,代码如下 代码2:
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case AppConfig.Login.GET_LINE_SUCCESS://分支获取成功
List<LineInfo> list = (List<LineInfo>) msg.obj;
if (list.size() > 0) {
login(list.get(0)); //登录
}
break;
case AppConfig.Login.GET_LINE_FAILED:
ToastUtils.showShort(getActivity(), "分支获取失败");
break;
case AppConfig.Login.LOGIN_SUCCESS:
ToastUtils.showShort(getActivity(), "登录成功");
requestResource();//获取资源
break;
case AppConfig.Login.LOGIN_FAILED:
ToastUtils.showShort(getActivity(), "视频登录失败");
break;
case MsgIds.GET_SUB_F_R_SUC:
break;
}
}
};
============================ ==============================================
//以下是状态类型
/**
* 登录逻辑相关常量
*/
public interface Login {
/**
* 获取线路成功
*/
int GET_LINE_SUCCESS = 0;
/**
* 获取线路失败
*/
int GET_LINE_FAILED = 1;
/**
* 显示进度
*/
int SHOW_LOGIN_PROGRESS = 2;
/**
* 取消进度提示
*/
int CANCEL_LOGIN_PROGRESS = 3;
/**
* 登录成功
*/
int LOGIN_SUCCESS = 4;
/**
* 登录失败
*/
int LOGIN_FAILED = 5;
/**
* 获取线路中
*/
int GET_LINE_IN_PROCESS = 6;
}
4、分支获取成功后就可以登录了,代码如下:
/**
* 登录视频服务器
*
* @param lineInfo
*/
private void login(final LineInfo lineInfo) {
new Thread() {
@Override
public void run() {
super.run();
String macAddress = CommonUtils.getMac(getActivity());
boolean ret = VMSNetSDK.getInstance().login(AppConfig.SERVER_URL, AppConfig.USERNAME, AppConfig.PASSWORD, lineInfo.lineID, macAddress, servInfo);
if (servInfo != null) {
// 打印出登录时返回的信息
Log.i(TAG, "login ret : " + ret);
Log.i(TAG, "login response info[" + "sessionID:" + servInfo.sessionID + ",userID:"
+ servInfo.userID + ",magInfo:" + servInfo.magInfo + ",picServerInfo:"
+ servInfo.picServerInfo + ",ptzProxyInfo:" + servInfo.ptzProxyInfo + ",userCapability:"
+ servInfo.userCapability + ",vmsList:" + servInfo.vmsList + ",vtduInfo:"
+ servInfo.vtduInfo + ",webAppList:" + servInfo.webAppList + "]");
}
if (ret) {
TempData.getIns().setLoginData(servInfo);
handler.sendEmptyMessage(AppConfig.Login.LOGIN_SUCCESS);
} else {
handler.sendEmptyMessage(AppConfig.Login.LOGIN_FAILED);
}
}
}.start();
}
登录时需要传入获取到的分支实体,因为当前我就一个分支,所以我取出来直接穿了一个LineInfo 对象。登录方法如下:VMSNetSDK.getInstance().login(AppConfig.SERVER_URL, AppConfig.USERNAME, AppConfig.PASSWORD, lineInfo.lineID, macAddress, servInfo)
在这个方法里面一共有6个参数,第一个是服务器地址,第二个是登录视频平台的用户名,第三个是登录视频平台的密码,第四个是分支ID,第五个是手机的mac地址, 第六个是该方法登录成功后获取到的视频服务器信息,保存在servInfo里面。该方法返回一个boolean类型,true登录成功,false 登录失败。
同样我也是用handler 处理的几种状态,代码在上面的Login 接口中。
5、请求视频资源树
public interface Resource {
/**
* 控制中心
*/
int TYPE_CTRL_UNIT = 1;
/**
* 区域
*/
int TYPE_REGION = 2;
/**
* 未知
*/
int TYPE_UNKNOWN = 3;
}
ResourceControl rc;
private int pResType = AppConfig.Resource.TYPE_UNKNOWN;//获取资源
private int pId = 0;
/**
* 请求资源
*/
private void requestResource() {
rc = new ResourceControl();
rc.setCallback(this);
rc.setCallback(new MsgCallback() {
@Override
public void onMsg(int msgId, Object data) {
Message msg = new Message();
msg.what = msgId;
msg.obj = data;
rcHandler.sendMessage(msg);
}
});
new Thread(new Runnable() {
@Override
public void run() {
rc.reqResList(pResType, pId);
}
}).start();
这段代码的意思是获取资源树 请求结果会反会到rc 注册的监听里面,然后通过handler具体处理,如下是整个rchandler
Handler rcHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
// 获取控制中心列表成功
case MsgIds.GET_C_F_NONE_SUC:
List<ControlUnitInfo> controlUnitInfoList = (List<ControlUnitInfo>) msg.obj;
if (controlUnitInfoList.size() > 0) {
pId = controlUnitInfoList.get(0).controlUnitID;
pResType = AppConfig.Resource.TYPE_CTRL_UNIT;
requestResource();
}
break;
// 从控制中心获取下级资源列表成功
case MsgIds.GET_SUB_F_C_SUC:
List<RegionInfo> regionInfoList = (List<RegionInfo>) msg.obj;
if (regionInfoList.size() > 0) {
pId = regionInfoList.get(0).controlUnitID;
pResType = AppConfig.Resource.TYPE_REGION;
requestResource();
}
break;
// 从区域获取下级列表成功
case MsgIds.GET_SUB_F_R_SUC:
cameraInfos = (List<CameraInfo>) msg.obj;
addrAdapter = new BaseAddrAdapter<>(getActivity(), cameraInfos);
spinner.setAdapter(addrAdapter);
break;
// 获取控制中心列表失败
case MsgIds.GET_C_F_NONE_FAIL:
// 调用getControlUnitList失败
case MsgIds.GET_CU_F_CU_FAIL:
// 调用getRegionListFromCtrlUnit失败
case MsgIds.GET_R_F_C_FAIL:
// 调用getCameraListFromCtrlUnit失败
case MsgIds.GET_C_F_C_FAIL:
// 从控制中心获取下级资源列表成失败
case MsgIds.GET_SUB_F_C_FAIL:
// 调用getRegionListFromRegion失败
case MsgIds.GET_R_F_R_FAIL:
// 调用getCameraListFromRegion失败
case MsgIds.GET_C_F_R_FAIL:
// 从区域获取下级列表失败
case MsgIds.GET_SUB_F_R_FAILED:
ToastUtils.showShort(getActivity(), "获取资源列表失败");
default:
break;
}
}
};
z这里可以看到 GET_C_F_NONE_SUC,GET_SUB_F_C_SUC,这里可以看到 GET_C_F_NONE_SUC 获取控制中心和获取控制中心下级资源列表成功后,并没有终止,而是再次调用requestResource方法,知道获取到区域下级列表才会停止。
这里我把集合数据放到了一个spinner 里面展示, 通过选择Spinner的Item 播放选中的视频,代码如下:
/**
* 初始化视频
*/
private void initData() {
mRealPlayURL = new RealPlayURL();
mLiveControl = new LiveControl();
mLiveControl.setLiveCallBack(this);
mDeviceID = cameraInfo.deviceID;
mVmsNetSDK = VMSNetSDK.getInstance();
DeviceInfo deviceInfo = new DeviceInfo();
if (mVmsNetSDK == null) {
CLog.e(TAG, "mVmsNetSDK is null");
return;
}
boolean ret = mVmsNetSDK.getDeviceInfo(SERVER_URL,
TempData.getIns().getLoginData().sessionID, mDeviceID, deviceInfo);
if (ret) {
name = deviceInfo.userName;
password = deviceInfo.password;
}
startPlayVideo();
}
/**
* 启动播放 void
*
* @since V1.0
*/
private void startPlayVideo() {
progressBar.setVisibility(View.VISIBLE);
new Thread() {
@Override
public void run() {
super.run();
mLiveControl.setLiveParams(getPlayUrl(2), mName, mPassword);
if (mLiveControl.LIVE_PLAY == mLiveControl.getLiveState()) {
mLiveControl.stop();
}
if (mLiveControl.LIVE_INIT == mLiveControl.getLiveState()) {
mLiveControl.startLive(surfaceView);
}
}
}.start();
}
/**
* 该方法是获取播放地址的,当mStreamType=2时,获取的是MAG,当mStreamType =1时获取的子码流,当mStreamType = 0时获取的是主码流
* 由于该方法中部分参数是监控点的属性,所以需要先获取监控点信息,具体获取监控点信息的方法见resourceActivity。
*
* @param streamType 2、表示MAG取流方式;1、表示子码流取流方式;0、表示主码流取流方式;
* @return String 播放地址 :2、表示返回的是MAG的播放地址;1、表示返回的是子码流的播放地址;0、表示返回的是主码流的播放地址。
* @since V1.0
*/
private String getPlayUrl(int streamType) {
String url = "";
// 登录平台地址
String mAddress = SERVER_URL;
// 登录返回的sessiond
String mSessionID = TempData.getIns().getLoginData().sessionID;
if (cameraInfo == null) {
LogUtils.i(TAG, "getPlayUrl():: cameraInfo is null");
return url;
}
if (streamType == 2) {
// TODO 原有代码streamType传0
VMSNetSDK.getInstance().getRealPlayURL(mAddress, mSessionID, cameraInfo.cameraID, streamType, mRealPlayURL);
if (null == mRealPlayURL) {
LogUtils.i(TAG, "getPlayUrl():: mRealPlayURL is null");
return "";
}
// MAG地址
url = mRealPlayURL.url2;
LogUtils.i(TAG, "getPlayUrl():: url is " + url);
} else {
VMSNetSDK.getInstance().getRealPlayURL(mAddress, mSessionID, cameraInfo.cameraID, streamType, mRealPlayURL);
if (null == mRealPlayURL) {
LogUtils.i(TAG, "getPlayUrl():: mRealPlayURL is null");
return "";
}
// mRealPlayURL.url1 是主码流还是子码流取决于 streamType,见上面注释
url = mRealPlayURL.url1;
LogUtils.i(TAG, "getPlayUrl():: url is " + url);
}
DeviceInfo deviceInfo = new DeviceInfo();
boolean ret = VMSNetSDK.getInstance().getDeviceInfo(mAddress, mSessionID, cameraInfo.deviceID, deviceInfo);
if (ret && deviceInfo != null) {
mName = deviceInfo.userName;
mPassword = deviceInfo.password;
} else {
LogUtils.i(TAG, "getPlayUrl():: deviceInfo is error");
}
return url;
}
播放视频的代码没啥好讲的了, 注释写的比较清楚了,
啊如下是停止播放视频的代码:
/**
* 停止播放 void
*
* @since V1.0
*/
private void stopLive() {
if (null != mLiveControl) {
mLiveControl.stop();
hidePlayBtn(true);
}
}
到此,视频就集成完了, 如果顺利 播放就可以看到视频了。