浏览代码

新增SDK回放测试类

25694 3 年之前
父节点
当前提交
4c5dacdb8d

+ 261 - 0
src/main/java/com/persagy/cameractl/controller/TestController.java

@@ -0,0 +1,261 @@
+package com.persagy.cameractl.controller;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.persagy.cameractl.service.HCNetSDKWindows;
+import com.persagy.cameractl.utils.Camera;
+import com.persagy.cameractl.utils.OtherTools;
+import com.persagy.cameractl.utils.ResultClass;
+import com.sun.jna.NativeLong;
+import com.sun.jna.ptr.IntByReference;
+
+import cn.hutool.core.date.DateUtil;
+
+@RestController
+public class TestController {
+	public static Logger logger = LoggerFactory.getLogger(TestController.class);
+	
+	private volatile boolean isInit = false;
+	
+	private volatile HCNetSDKWindows hcNetSdk;
+	
+	@RequestMapping(value = "/test", method = RequestMethod.POST)
+	public ResultClass hello(@RequestBody Camera camera) {
+		ResultClass returnResult = new ResultClass();
+		String targetFile = OtherTools.getVideoFilePath();
+		returnResult.name = false;
+		if (targetFile.equals("")) {
+			returnResult.reason = "回放文件名称生成失败";
+			return returnResult;
+		}
+		logger.info("回放文件地址:" + targetFile);
+		
+		File mp4File = new File(targetFile);
+		String targetFileName = mp4File.getName();
+		File fileParent = mp4File.getParentFile();
+		String targetFilePath = fileParent.getPath();
+		
+		// SDK初始化
+		boolean init = this.init();
+		if (!init) {
+			returnResult.reason = "SDK初始化失败";
+			return returnResult;
+		}
+		
+		// 文件下载,这里不使用原文件,因为还需要转码
+		String downloadFile = targetFilePath + "/_" + targetFileName;
+		String downloadVideo = this.downloadVideo(camera, downloadFile);
+		if (!"true".equals(downloadVideo)) {
+			returnResult.reason = downloadVideo;
+			return returnResult;
+		}
+		
+		try {
+			// 转码
+			Map<String, String> data = new HashMap<String, String>(4);
+			convetorVideo(downloadFile, targetFile);
+			data.put("url", OtherTools.playMp4RootUrl + OtherTools.getMp4NamePrefix(targetFileName));
+			returnResult.resultData = data;
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		
+		returnResult.name = true;
+		returnResult.reason = "回放文件生成成功";
+		return returnResult;
+	}
+	
+	/**
+	 * 按时间进行视频下载,实现回放
+	 * 
+	 * @param Camera 请求参数
+	 * @param filePath 文件路径,包含文件名称及后缀
+	 * @param channel 通道号
+	 * @return
+	 */
+    private String downloadVideo(Camera camera, String filePath) {
+		// 注册设备 -1表示失败,其他值表示返回的用户ID值。接口返回失败请调用NET_DVR_GetLastError获取错误码,通过错误码判断出错原因。
+		HCNetSDKWindows.NET_DVR_DEVICEINFO_V30 m_strDeviceInfo = new HCNetSDKWindows.NET_DVR_DEVICEINFO_V30();
+		NativeLong lUserID = hcNetSdk.NET_DVR_Login_V30(camera.cameraIp, (short) camera.cameraPort, camera.userName, camera.password, m_strDeviceInfo);
+
+		// 注册失败
+		if (lUserID.longValue() == -1) {
+			int errCode = hcNetSdk.NET_DVR_GetLastError();
+			// 返回失败时的错误码
+			return "设备注册失败,失败码:" + errCode;
+		}
+    	
+		// 准备文件下载
+    	NativeLong loadHandle = hcNetSdk.NET_DVR_GetFileByTime(lUserID, new NativeLong(camera.channel), getHkTime(camera.startDateStr), getHkTime(camera.endDateStr), filePath);
+        logger.info("hksdk(视频)-获取播放句柄信息,状态值:" + hcNetSdk.NET_DVR_GetLastError());
+        
+        if (loadHandle.intValue() >= 0) {
+            // 判断文件夹是否存在
+            File files = new File(filePath);
+            if(!files.exists()){
+                files.mkdirs();
+            }
+            
+            hcNetSdk.NET_DVR_PlayBackControl(loadHandle, HCNetSDKWindows.NET_DVR_PLAYSTART, 0, null);
+            
+            int tmp = -1;
+            IntByReference pos = new IntByReference();
+            while (true) {
+                boolean backFlag = hcNetSdk.NET_DVR_PlayBackControl(loadHandle, HCNetSDKWindows.NET_DVR_PLAYGETPOS, 0, pos);
+                if (!backFlag) {
+                    break;
+                }
+                int produce = pos.getValue();
+                if ((produce % 10) == 0 && tmp != produce) {//输出进度
+                    tmp = produce;
+                    logger.info("hksdk(视频)-视频下载进度:" + "==" + produce + "%");
+                }
+                if (produce == 100) {//下载成功
+                	hcNetSdk.NET_DVR_StopGetFile(loadHandle);
+                    hcNetSdk.NET_DVR_Logout(lUserID);//退出录像机
+                    logger.info("hksdk(视频)-退出状态" + hcNetSdk.NET_DVR_GetLastError());
+                    //hcNetSdk.NET_DVR_Cleanup();	// 这里不进行释放
+                    return "true";
+                }
+                if (produce > 100) { //下载失败,异常终止,这时返回true
+                	hcNetSdk.NET_DVR_StopGetFile(loadHandle);
+                    int net_DVR_GetLastError = hcNetSdk.NET_DVR_GetLastError();
+                    logger.warn("hksdk(视频)-海康sdk由于网络原因或DVR忙,下载异常终止! 错误原因:" + net_DVR_GetLastError);
+                    hcNetSdk.NET_DVR_Logout(lUserID);//退出录像机
+                    return "true";
+                }
+            }
+        }
+        
+    	int net_DVR_GetLastError = hcNetSdk.NET_DVR_GetLastError();
+        logger.error("hksdk(视频)-下载失败,失败码" + net_DVR_GetLastError);
+        return "文件下载失败,失败码:" + net_DVR_GetLastError;
+    }
+
+    /**
+     * 初始化SDK
+     * 
+     * @return
+     */
+	private boolean init() {
+		if (!isInit) {
+			// 初始化
+			hcNetSdk = HCNetSDKWindows.INSTANCE;
+			isInit = hcNetSdk.NET_DVR_Init();
+		}
+		return isInit;
+	}
+	
+    /**
+     * 获取海康录像机格式的时间
+     */
+    private HCNetSDKWindows.NET_DVR_TIME getHkTime(String timeParam) {
+    	Date time = DateUtil.parse(timeParam);
+    	
+        HCNetSDKWindows.NET_DVR_TIME dvrTime = new HCNetSDKWindows.NET_DVR_TIME();
+        dvrTime.dwYear = DateUtil.year(time);
+        dvrTime.dwMonth = DateUtil.month(time) + 1;
+        dvrTime.dwDay = DateUtil.dayOfMonth(time);
+        dvrTime.dwHour = DateUtil.hour(time, true);
+        dvrTime.dwMinute = DateUtil.minute(time);
+        dvrTime.dwSecond = DateUtil.second(time);
+		
+        return dvrTime;
+    }
+    
+    /**
+     * 文件转码
+     * 
+     * @param videoInputFile
+     * @param videoOutFile
+     * @throws Exception
+     */
+    public static void convetor(String videoInputFile, String videoOutFile) throws Exception {
+    	File sourceFile = new File(videoInputFile);
+
+		// 把源MP4转为页面上可播放的MP4
+		Runtime run = Runtime.getRuntime();
+		Process p = run.exec("ffmpeg -i \"" + videoInputFile + "\" -c copy -y \"" + videoOutFile + "\"");
+
+		// 读取标准输入流、输出流,防止进程阻塞
+		// 标准输入流(必须写在 waitFor 之前)
+		String inputStreamStr = OtherTools.consumeInputStream(p.getInputStream());
+		// 标准错误流(必须写在 waitFor 之前)
+		String errStreamStr = OtherTools.consumeInputStream(p.getErrorStream());
+
+		int retCode = p.waitFor();
+		if (retCode != 0) {
+			String errStr = errStreamStr != null ? errStreamStr : inputStreamStr;
+			logger.error("ffmpeg转换mp4时失败,错误信息:" + errStr);
+		}
+		p.destroy();
+		sourceFile.delete();
+    }
+	
+    /**
+     * 文件转码
+     * 
+     * @param videoInputFile
+     * @param videoOutFile
+     * @throws Exception
+     */
+    @SuppressWarnings("unused")
+	public static void convetorVideo(String videoInputFile, String videoOutFile) throws Exception {
+        List<String> command = new ArrayList<String>();
+        command.add("ffmpeg");
+        command.add("-i");
+        command.add(videoInputFile);
+        command.add("-c");
+        command.add("copy");
+        command.add("-an");
+        command.add(videoOutFile);
+        ProcessBuilder builder = new ProcessBuilder(command);
+        Process process = null;
+        try {
+            process = builder.start();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        // 使用这种方式会在瞬间大量消耗CPU和内存等系统资源,所以这里我们需要对流进行处理
+        InputStream errorStream = process.getErrorStream();
+        InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
+        BufferedReader br = new BufferedReader(inputStreamReader);
+        String line = "";
+        while ((line = br.readLine()) != null) {
+        }
+        if (br != null) {
+            br.close();
+        }
+        if (inputStreamReader != null) {
+            inputStreamReader.close();
+        }
+        if (errorStream != null) {
+            errorStream.close();
+        }
+    	
+    	File sourceFile = new File(videoInputFile);
+		sourceFile.delete();
+    }
+    
+    public static void main(String[] args) throws Exception {
+    	//convetor("C:\\Users\\25694\\Desktop\\testffmepg\\sss.mp4", "C:\\Users\\25694\\Desktop\\testffmepg\\demo.mp4");
+    	convetorVideo("C:\\Users\\25694\\Desktop\\testffmepg\\sss.mp4", "C:\\Users\\25694\\Desktop\\testffmepg\\demoss.mp4");
+	}
+    
+}

文件差异内容过多而无法显示
+ 1391 - 1396
src/main/java/com/persagy/cameractl/service/HaiKMainWindows.java