java通过jna调用C++接口介绍
java通过jna调用C++接口介绍
最近在做项目有一个需求是需要实现基于 JS 无插件的视频播放,因此涉及到HPSClientSDK的调用,就需要用java程序对C++接口进行调用。
java调用c++方式
在Java程序中调用C++服务通常有以下4种方式:
- JNI(Java Native Interface)
①通过JNI可以在Java代码中调用C/C++代码,是最直接的调用方式。
②需要用C/C++实现对native方法的实现,使用JNI类型转换把Java数据转换成C/C++可用的数据。
③配置好头文件,库文件,然后通过System.loadLibrary加载native库。 - JNA(Java Native Access)
①JNA可以直接调用C库而不需要JNI写native方法。
②使用接口绑定的方式动态链接C库,直接调用C函数和结构体。
③需要配置JNA jar包,比JNI使用更简单。 - 通过网络调用
①Java通过网络请求调用C++开发的服务端程序。
②C++服务端可以通过socket,rpc框架开发服务,Java通过网络协议调用服务。
③通过网络分离语言层,部署更灵活。 - 通过JNI封装网络调用接口
①通过JNI封装对C++服务网络调用接口的包装。
②Java层调用JNI接口,JNI接口通过网络请求调用C++服务。
③结合JNI和网络调用优点,Java层看似直接调用C++服务。
本项目选择的是JNA调用方式。接下来主要介绍一下JNA调用方式。
hpsclient的lib依赖库文件下载 - 需要在本地resource目录下传hpsclient的lib库文件
下载后解压,在压缩包的bin目录下拷贝所有lib库文件
Linux的lib库文件
Windows的lib库文件
hpsclient的lib依赖库文件导入项目路径以及日志输出配置
1.linux库文件:拷贝后的lib库文件,存放到start》src》main》resources,在resources目录下可以新建一个hpsclient的文件夹,在hpsclient》linux》bin中添加lib库文件
2. 需要在start》src》main》resources》hpsclient》linux》bin下添加log4cxx.properties
3.需要在log4cxx.properties中修改一下日志的输出路径,可以参考如下设置:
进行上述日志输出路径配置后,安装服务器上,hpsclient日志输出路径
3. start》src》assembly下assembly.xml中配置安装组件安装到服务器后,hpsclient的lib库文件存放位置
assembly.xml文件是Maven Assembly Plugin插件的配置文件,它用于配置项目打包相关的信息,主要用于生成项目分发包。assembly.xml的作用主要有:
① 定义项目分发包类型:比如jar、zip包等。
② 指定分发包的名称和存放位置。
③ 指定需要包含在分发包里面的文件。
④ 排除不需要打包的文件。
⑤ 配置分发包的依赖等信息。
⑥ 配置分发包构建时的过滤、替换等操作。
⑦ 指定分发包的格式化、压缩方式等。
⑧ 继承其他assembly配置以复用配置。
4.windows库文件:拷贝后的lib库文件,存放到start》src》main》resources,在resources目录下可以新建一个hpsclient的文件夹,在hpsclient》windows》bin中添加lib库文件
jna调用C++接口
使用JNA(Java Native Access)在Java中调用C++代码的基本步骤:
- 引入jna依赖
<!--jna库-->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.2.2</version>
</dependency>
- 定义C++接口
① 创建一个Java接口,定义需要调用HPSClient中需要调用的C++函数
public interface HPSClientLibrary extends Library {
/**sdk初始化接口*/
int HPSClient_InitLib();
/**sdk反初始化接口*/
int HPSClient_FiniLib();
/**创建RTSP会话接口*/
int HPSClient_CreateSession();
/**开启实时推流接口*/
int HPSClient_PushData(int sessionhandle, String url, String useragent, int transmethod, String deviceusername, String devicepasswd, String destip, int destport);
/**设置消息回调*/
int HPSClient_SetMsgCallBack(int sessionhandle, HPSClientMsgFunc pMsgFunc, Pointer userdata);
/**设置会话参数*/
int HPSClient_SetSessionParams(int sessionhandle, String usrmsg, int len);
/**强制I帧*/
int HPSClient_ForceIFrame(int sessionhandle);
/**停止取流接口*/
int HPSClient_Stop(int sessionhandle);
/**销毁RTSP会话接口*/
int HPSClient_DestroySession(int sessionhandle);
/**
* 获取会话取流失败错误码
* 接口返回失败后需要调用获取接口失败错误码接口
*/
int HPSClient_GetLastError();
/**
* 改变回放/下载速度接口
*/
int HPSClient_ChangeRate(int sessionhandle, float scale);
/**
* 暂停回放接口
*/
int HPSClient_Pause(int sessionhandle);
/**
* 恢复回放接口
*/
int HPSClient_Resume(int sessionhandle);
/**
* 恢复回放接口
*/
int HPSClient_RandomPlayByAbsEx(int sessionhandle, String from, String to);
int HPSClient_GetLastError(int sessionhandle);
}
② 创建消息回调结构体。
public interface PStreamClientMsgCallback extends Callback {
int pHPSClientMsgFunc(int session, Pointer userdata, int opt, Pointer param1, Pointer param2, Pointer param3, Pointer param4);
}
@Component
public class HPSClientMsgFunc implements PStreamClientMsgCallback {
private static final Logger LOGGER = LoggerFactory.getLogger(HPSClientMsgFunc.class);
protected static final Map<String,Object> IP_PORT_MAP = new ConcurrentHashMap<>();
@Override
public int pHPSClientMsgFunc(int session, Pointer userdata, int opt, Pointer param1, Pointer param2,
Pointer param3, Pointer param4) {
LOGGER.debug("receive message call back, session is = " + session + ", opt is " + opt + ", param1 is " + param1 + ", param2 is " + param2);
if (session < 0) {
return 0;
}
//HPS_MSGOPT_SERVER_TCP_ADDR==1 表示TCP 推流下 serverIP 和端口。(通知)
if (opt == 1) {
short portShort = param1.getShort(0);
LOGGER.debug("port short:{}",portShort);
int port = Short.valueOf(portShort).intValue();
LOGGER.debug("port :{}",port);
IP_PORT_MAP.put("port", port);
String ip = param2.getString(0);
IP_PORT_MAP.put("ip", ip);
}
return 0;
}
}
- 实现接口
① 不需要实现接口,JNA会动态绑定到C++的实现。 - 加载C++库
① 使用Native.loadLibrary加载C++的动态库或静态库。 - 调用方法
①直接调用Java接口定义的方法,JNA会跨语言调用C++实现。
上述四步执行完就完成了java通过jna调用C++接口功能。
具体实现代码可以参考如下HPSClientUtil工具类:
@Component
public class HPSClientUtil {
protected static AriesJcLogger LOGGER = AriesJcLoggerFactory.getLogger(HPSClientUtil.class);
static HPSClientLibrary INSTANCE;
@Autowired
private HPSClientMsgFunc hpsClientMsgFunc;
@Autowired
private RedisTool redisTool;
@PostConstruct
public void init(){
if(OsInfoTool.isLinux()){
LOGGER.info(System.getProperty("java.library.path"));
INSTANCE = (HPSClientLibrary) Native.loadLibrary("HPSClient", HPSClientLibrary.class);
LOGGER.debug("HPSClient init --> os is linux.");
initLib();
}else if(OsInfoTool.isWindows()){
INSTANCE = (HPSClientLibrary) Native.loadLibrary("D:\\媒体服务\\HPSClient_5.11.18.0_windows_vc2008_x86_64\\bin\\HPSClient.dll", HPSClientLibrary.class);
LOGGER.debug("HPSClient init --> os is windows.");
initLib();
}
}
/**
* @param
* @return void
* @author hemanman6
* @description 初始化
* @date 2023/8/30 10:11
*/
public void initLib(){
int initLib = INSTANCE.HPSClient_InitLib();
LOGGER.debug("HPSClient_InitLib is {}",initLib);
if(initLib!=0){
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_InitLib获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
}
/**
* @param
* @return void
* @author hemanman6
* @description 反初始化
* @date 2023/8/30 10:12
*/
public void finiLib(){
int finiLib = INSTANCE.HPSClient_FiniLib();
LOGGER.debug("HPSClient_FiniLib is {}",finiLib);
if(finiLib!=0){
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_FiniLib获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
}
public void getRecordPlaybackControl(String token,Integer controlType, Integer controlParam){
try {
//初始化
// initLib();
//创建会话
// int sessionHandle = INSTANCE.HPSClient_CreateSession();
//从TokenMapValue获取sessionHanle
//获取token对应的sessionHandle
TokenMapValue tokenMapValue = (TokenMapValue)redisTool.get(token);
LOGGER.debug("getRecordPlaybackControl tokenMapValue:{}",JSON.toJSONString(tokenMapValue));
if(!Optional.ofNullable(tokenMapValue).isPresent()){
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getErrorCode(),
"获取getRecordPlaybackControl tokenMapValue为空");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getChMsg());
}
Integer sessionHandle = tokenMapValue.getSessionHandle();
LOGGER.debug("录像回放控制sessionHandle is {}", sessionHandle);
if(sessionHandle<0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"录像回放控制HPSClient_CreateSession获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
if(STOP.equals(controlType)){
//销毁会话
int destroySession = INSTANCE.HPSClient_DestroySession(sessionHandle);
LOGGER.debug("录像回放控制destroySession is {}", destroySession);
if(destroySession!=0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_DestroySession获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
}else if(PAUSE.equals(controlType)){
int pasuse = INSTANCE.HPSClient_Pause(sessionHandle);
LOGGER.debug("录像回放控制pasuse is {}", pasuse);
if(pasuse!=0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_Pause获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
}else if(RESUME.equals(controlType)){
int resume = INSTANCE.HPSClient_Resume(sessionHandle);
LOGGER.debug("录像回放控制resume is {}", resume);
if(resume!=0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_Resume获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
}else if(RATE_FRONT.equals(controlType)){
float scale = getPlaybackRate(controlParam);
LOGGER.debug("速度scale:{}",scale);
int changeRate = INSTANCE.HPSClient_ChangeRate(sessionHandle, scale);
LOGGER.debug("录像回放控制changeRate is {}", changeRate);
if(changeRate!=0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_ChangeRate获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
}else if(RATE_BACK.equals(controlType)){
float scale = getPlaybackRate(controlParam);
int changeRate = INSTANCE.HPSClient_ChangeRate(sessionHandle, scale);
LOGGER.debug("录像回放控制changeRate is {}", changeRate);
if(changeRate!=0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_ChangeRate获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
}else if(DELAY.equals(controlType)){
if(redisTool.exist("token_"+token)){
PlaybackTime playbackTime = (PlaybackTime)redisTool.get("token_" + token);
String kssj = playbackTime.getKssj();
//计算开始的偏移时间
String from = DateTool.afterDate(kssj, controlParam);
String jssj = playbackTime.getJssj();
int changeRate = INSTANCE.HPSClient_RandomPlayByAbsEx(sessionHandle, from,jssj);
LOGGER.debug("录像回放控制RandomPlayByAbsEx is {}", changeRate);
if(changeRate!=0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_RandomPlayByAbsEx获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
}
}
//反初始化
// finiLib();
} catch (Exception e) {
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
}
/**
* @param controlParam
* @return float
* @author hemanman6
* @description 播放控制速率转换
* @date 2023/9/1 17:16
*/
public float getPlaybackRate(Integer controlParam){
float scale = 0.0f;
if(HALF_RATE.equals(controlParam)){
scale = 0.5f;
}else if(QUARTER_RATE.equals(controlParam)){
scale = 0.25f;
}else if(EIGHTH_RATE.equals(controlParam)){
scale = 0.125f;
}else if(ONE_RATE.equals(controlParam)){
scale = 1.0f;
}else if(TWO_RATE.equals(controlParam)){
scale = 2.0f;
}else if(FOUR_RATE.equals(controlParam)){
scale = 4.0f;
}else if(EIGHT_RATE.equals(controlParam)){
scale = 8.0f;
}
return scale;
}
/**
* @param url
* @return String
* @author hemanman6
* @description push_data获取媒体的ip和port 实时预览
* @date 2023/8/30 10:15
*/
public String getRealTimeMgcTcpRawUrl(String token,String url){
String tcpRawUrl = "";
try {
//初始化
// initLib();
//实时推流流程
//从TokenMapValue获取sessionHanle
//获取token对应的sessionHandle
TokenMapValue tokenMapValue = (TokenMapValue)redisTool.get(token);
if(!Optional.ofNullable(tokenMapValue).isPresent()){
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getChMsg());
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getChMsg());
}
Integer sessionHandle = tokenMapValue.getSessionHandle();
//创建会话
// int sessionHandle = INSTANCE.HPSClient_CreateSession();
LOGGER.debug("实时推流sessionHandle is {}", sessionHandle);
if(sessionHandle<0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"实时推流sessionHandle获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
Map<String, String> map = getIpAndPort(url);
LOGGER.debug("获取ip、port与restUrl的map:{}", JSON.toJSONString(map));
if(!Optional.ofNullable(map).isPresent()){
LOGGER.error("获取ip、port与restUrl的map为空");
}
String destip = map.get("destip");
String portString = map.get("destport");
String restUrl = map.get("restUrl");
Integer destport = Integer.valueOf(portString);
//设置消息回调
LOGGER.debug("HPSClient_SetMsgCallBack sessionHandle is {}", sessionHandle);
int msgCallBackResult = INSTANCE.HPSClient_SetMsgCallBack(sessionHandle, hpsClientMsgFunc, null);
if(msgCallBackResult!=0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_SetMsgCallBack获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
//开启推流请求,并返回媒体ip和端口
int pushDataResult = INSTANCE.HPSClient_PushData(sessionHandle, url, "HPSClient", 0x9003, null, null,
destip, destport);
LOGGER.debug("HPSClient_PushData 结果 is {}", pushDataResult);
if(pushDataResult!=0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_PushData获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
//否则获取ip和port
String ip = (String)IP_PORT_MAP.get("ip");
Integer port = (Integer) IP_PORT_MAP.get("port");
LOGGER.debug("返回媒体的ip是:{},port是:{}",ip,port);
//组装成tcpraw类型的url
tcpRawUrl = "tcpraw://"+ip+":"+port+restUrl;
LOGGER.debug("tcpRawUrl:{}",tcpRawUrl);
} catch (Exception e) {
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
return tcpRawUrl;
}
/**
* @param url
* @return String
* @author hemanman6
* @description 回放取流url
* @date 2023/9/8 17:21
*/
public String getPlaybackMgcTcpRawUrl(String token,String url){
String tcpRawUrl = "";
try {
//初始化
// initLib();
//实时推流流程
//创建会话
// int sessionHandle = INSTANCE.HPSClient_CreateSession();
//从TokenMapValue获取sessionHanle
//获取token对应的sessionHandle
TokenMapValue tokenMapValue = (TokenMapValue)redisTool.get(token);
if(!Optional.ofNullable(tokenMapValue).isPresent()){
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getChMsg());
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getChMsg());
}
Integer sessionHandle = tokenMapValue.getSessionHandle();
LOGGER.debug("回放取流sessionHandle is {}", sessionHandle);
if(sessionHandle<0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"回放取流sessionHandle获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
Map<String, String> map = getIpAndPort(url);
LOGGER.debug("获取ip、port与restUrl的map:{}", JSON.toJSONString(map));
if(!Optional.ofNullable(map).isPresent()){
LOGGER.error("获取ip、port与restUrl的map为空");
}
String destip = map.get("destip");
String portString = map.get("destport");
String restUrl = map.get("restUrl");
Integer destport = Integer.valueOf(portString);
//设置消息回调
int msgCallBackResult = INSTANCE.HPSClient_SetMsgCallBack(sessionHandle, hpsClientMsgFunc, null);
if(msgCallBackResult!=0){
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_SetMsgCallBack获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
//开启推流请求,并返回媒体ip和端口
int pushDataResult = INSTANCE.HPSClient_PushData(sessionHandle, url, "HPSClient", 0x9003, null, null,
destip, destport);
LOGGER.debug("HPSClient_PushData 结果 is {}", pushDataResult);
if(pushDataResult!=0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_PushData获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
//否则获取ip和port
String ip = (String)IP_PORT_MAP.get("ip");
Integer port = (Integer) IP_PORT_MAP.get("port");
LOGGER.debug("返回媒体的ip是:{},port是:{}",ip,port);
//组装成tcpraw类型的url
tcpRawUrl = "tcpraw://"+ip+":"+port+restUrl;
LOGGER.debug("tcpRawUrl:{}",tcpRawUrl);
} catch (Exception e) {
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
return tcpRawUrl;
}
/**
* @author hemanman6
* @description 停止取流
* @date 2023/9/1 13:48
*/
public void realtimeStop(String token){
//初始化
// initLib();
//创建会话
//从TokenMapValue获取sessionHanle
//获取token对应的sessionHandle
TokenMapValue tokenMapValue = (TokenMapValue)redisTool.get(token);
if(!Optional.ofNullable(tokenMapValue).isPresent()){
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getChMsg());
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1010.getChMsg());
}
Integer sessionHandle = tokenMapValue.getSessionHandle();
// int sessionHandle = INSTANCE.HPSClient_CreateSession();
LOGGER.debug("实时停止取流sessionHandle is {}", sessionHandle);
if(sessionHandle<0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"实时停止取流sessionHandle获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
//停止推流
int hpsClientStop = INSTANCE.HPSClient_Stop(sessionHandle);
if(hpsClientStop!=0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_Stop获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
//销毁会话
INSTANCE.HPSClient_DestroySession(sessionHandle);
//反初始化
finiLib();
}
/**
* 错误回调
*/
public void errorMessage(Integer sessionHandle) {
try {
int err = INSTANCE.HPSClient_GetLastError(sessionHandle);
String hexString = "0x0"+Integer.toHexString(err);
LOGGER.info("错误码为:{}", hexString);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
/**
* 销毁会话,销毁当前token的会话对应sessionHandle
*/
public void destorySession(Integer sessionHandle){
int destroySession = INSTANCE.HPSClient_DestroySession(sessionHandle);
if(destroySession<0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_DestroySession获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
}
/**
* 销毁会话,销毁当前token的会话对应sessionHandle
*/
public int createSession(){
int sessionHandle = INSTANCE.HPSClient_CreateSession();
if(sessionHandle<0){
errorMessage(sessionHandle);
LOGGER.errorWithErrorCode(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(),"HPSClient_CreateSession获取失败");
throw new BusinessException(VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getErrorCode(),
VdmvnpsErrorCodeEnum.VIDEO_ONLINE_ERROR_CODE_1012.getChMsg());
}
return sessionHandle;
}
public void setMsgCallBack(Integer sessionHandle){
//设置消息回调
int msgCallBackResult = INSTANCE.HPSClient_SetMsgCallBack(sessionHandle, hpsClientMsgFunc, null);
if (msgCallBackResult != 0) {
errorMessage(sessionHandle);
throw new BusinessException(VdmvnpsErrorCodeEnum.OTHER_ERROR.getErrorCode(), "HPSClient_SetMsgCallBack获取失败");
}
}
public static void main(String[] args) {
String url = "rtsp://10.5.160.103:6304/EUrl/qFD77n9";
String[] urlSplit = url.split("://");
String[] split = urlSplit[1].split("/")[0].split(":");
String ip = split[0];
System.out.println(ip);
String port = split[1];
System.out.println(port);
String s = urlSplit[1].split("/")[1];
String s1 = urlSplit[1].split("/")[2];
System.out.println(s);
System.out.println(s1);
String hexString = "0x0"+Integer.toHexString(24373874);
System.out.println("10进制转16进制: "+hexString);
}
/**
* @param url
* @return null
* @author hemanman6
* @description
* @date 2023/8/29 15:18
*/
public Map<String, String> getIpAndPort(String url) {
Map<String, String> map = new HashMap();
if (StringUtils.isNotBlank(url)) {
String[] urlSplit = url.split("://");
if (Optional.ofNullable(urlSplit).isPresent()) {
String[] split = urlSplit[1].split("/")[0].split(":");
String restUrl = "/"+urlSplit[1].split("/")[1]+"/"+ urlSplit[1].split("/")[2];
if (Optional.ofNullable(split).isPresent()) {
String ip = split[0];
String port = split[1];
map.put("destip", ip);
map.put("destport", port);
map.put("restUrl",restUrl);
}
}
}
return map;
}
}
jna调用C++接口调用过程出现的问题
1.vdmvnps安装平台后,调用实时录像接口报错找不到hpsclient的lib库文件
出现该问题是没有在assembly.xml中生成hpsclient生成的jna文件路径,导致在linux服务器上找不到jna调用lib库文件地址
2.本地测试通过windows调用hpsclient推流接口返回tcp协议的端口号小于65535,而安装平台linux环境调用hpsclient推流接口返回tcp协议的端口号就超过65535导致不能获取实时视频流
排查发现导致这种产生的原因是:在Linux下,Pointer param1指向一个小端序的32位int,值是534424。但是在Windows下,同样的指针所指向的int类型可能是16位短整型(short),最大值就是65535。因此在Windows下解析时,获取的值被限制为了16位短整型的范围。
具体修改方法:
在Linux环境下用short类型接收端口号值,这样就不会超过65535
更多推荐




所有评论(0)