|
@@ -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");
|
|
|
+ }
|
|
|
+
|
|
|
+}
|