提示
java使用 SpringBoot 框架
jdk使用 1.8版本
海康
通过访问 OpenAPI 文档中心的方式可以验证 API 网关是否安装成功,访问地址
http://IP:Port/artemis-portal/document 打开文档中心(其中 IP:Port 以及 http 头与登录门户页面信息保
持一致)。
相关文件
开发准备
环境
ip,prot
门户登录地址,注意端口要和所选的协议匹配(http 默认端口 80,https 默认 端口 443,如有修改,以实际端口为准);
参数
appkey ,secret
Appkey/Secret:合作方 Key 和 Secret(从运管中心-状态监控-API 网关-API 管理-合作方 管理,点开具体合作方获得);
工具使用
-
视频WEB插件
浏览器插件播放
-
OpenApi 签名生成工具
根据签名使用postman调用调试
X-Ca-Key:appKey,即 AK。
X-Ca-Signature:签名,以 appSecret(即 SK)为密钥,
X-Ca-Signature-Headers:请求头,填写有值字段
以上字段为必填值
获取签名 使用postman调取接口
- OpenAPI 接口测试工具
根据参数直接调取
引入海康依赖
pom.xml
<dependency>
<groupId>com.hikvision.ga</groupId>
<artifactId>artemis-http-client</artifactId>
<version>1.1.3</version>
</dependency>
java文件
package com.landy.framework.web.controller;
// 引入类
import com.alibaba.fastjson.JSONObject;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.hikvision.artemis.sdk.ArtemisHttpUtil;
import com.hikvision.artemis.sdk.config.ArtemisConfig;
import com.landy.framework.common.Response; //自定义 Spring Boot 相应包
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
获取监控列表
@RestController
@RequestMapping("/api/camera")
@Api(tags = "1-海康威视接口")
@ApiSupport(order = 1)
public class TWaternetCameraController {
@ApiOperation(value = "1-查询视频列表", notes = "调用海康威视接口查询视频列表")
@GetMapping("/cameraSearch")
public Response cameraSearch(Integer pageNo, Integer pageSize) {
return Response.ok(this.GetCameraPreviewURL("/api/resource/v2/encodeDevice/search", null, pageNo, pageSize));
}
@ApiOperation(value = "2-查询摄像头视频流", notes = "调用海康威视接口查询摄像头视频流")
@GetMapping("/cameraPreviewUrl")
public Response cameraPreviewUrl(String cameraCode) {
return Response.ok(this.GetCameraPreviewURL("/api/video/v1/cameras/previewURLs", cameraCode, null, null));
}
public String GetCameraPreviewURL(String url, String indexCodes, Integer pageNo, Integer pageSize) {
/*
url 根据官方文档或提供接口切换
*/
/**
* STEP1:设置平台参数,根据实际情况,设置host appkey appsecret 三个参数.
* {appkey:"******",secret:"******",ip:"***",port:***
*/
ArtemisConfig.host = "ip:port"; // artemis网关服务器ip端口
ArtemisConfig.appKey = "******"; // 秘钥appkey
ArtemisConfig.appSecret = "******";// 秘钥appSecret
/**
* 两种都可
*
ArtemisConfig artemisConfig = new ArtemisConfig();
artemisConfig.setHost("ip:port"); //平台(nginx)IP和端口
artemisConfig.setAppKey("******"); //合作方key
artemisConfig.setAppSecret("******");//合作方Secret
*/
/**
* STEP2:设置OpenAPI接口的上下文
*/
final String ARTEMIS_PATH = "/artemis";
/**
* STEP3:设置接口的URI地址
*/
final String previewURLsApi = ARTEMIS_PATH + url;
Map<String, String> path = new HashMap<String, String>(2) {
{
put("https://", previewURLsApi);//根据现场环境部署确认是http还是https
}
};
/**
* STEP4:设置参数提交方式
*/
String contentType = "application/json";
/**
* STEP5:组装请求参数
*/
JSONObject jsonBody = new JSONObject();
// jsonBody.put("userId", "***");
// jsonBody.put("cameraIndexCode", "***");
// jsonBody.put("streamType", 0);
// jsonBody.put("protocol", "rtsp");
// jsonBody.put("transmode", 1);
// jsonBody.put("expand", "streamform=ps");
if (StringUtils.isNotBlank(indexCodes)) {
// jsonBody.put("cameraIndexCode", new String[]{indexCodes});
jsonBody.put("cameraIndexCode", indexCodes);
jsonBody.put("protocol", "rtsp");
} else {
if (pageNo == null) {
pageNo = 1;
}
if (pageSize == null) {
pageSize = 1000;
}
jsonBody.put("pageNo", pageNo);
jsonBody.put("pageSize", pageSize);
}
String body = jsonBody.toJSONString();
/**
* STEP6:调用接口
*/
String result = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null,
contentType, null);// post请求application/json类型参数
return result;
}
}
ffmpeg转换视频流
视频流可获取 hls 格式不需要转换
java文件
package com.landy.framework.web.controller;
// 引入类
import com.alibaba.fastjson.JSONObject;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.hikvision.artemis.sdk.ArtemisHttpUtil;
import com.hikvision.artemis.sdk.config.ArtemisConfig;
import com.landy.framework.common.Response; //自定义 Spring Boot 相应包
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
视频流转换
使用ffmpeg转换视频流 可自定义转换格式
@RestController
@RequestMapping("/api/camera")
@Api(tags = "2-视频流转换")
@ApiSupport(order = 1)
public class videoStreamController {
private FileUtil fileUtil;
@Value("${mapFile.path}") // 存储地址
private String filePath;
@Value("${mapFile.address}") // 外层文件夹名
private String address;
@Value("${mapFile.ip}") // 映射ip
private String ip;
@ApiOperation(value = "1-RTSP转HLS视频流", notes = "调用FFmpeg转视频流")
@GetMapping("/changePreviewUrl")
public Response changePreviewUrl(String rtspUrl, String codeName) {
this.stopFFmpeg();
return Response.ok(this.GetCameraPreviewURL(rtspUrl, codeName));
}
@ApiOperation(value = "2-停止视频流转换", notes = "停止FFmpeg转视频流")
@GetMapping("/stopPreviewUrl")
public Response stopPreviewUrl() {
return Response.ok(this.stopFFmpeg());
}
private Process ffmpegProcess;
private String outputName = "";
public String GetCameraPreviewURL(String url, String codeName) {
// 工作目录
String currentPath = System.getProperty("user.dir");
// 获取当前类的路径
// String classPath = GetClassPathExample.class.getResource("/").getPath();
// 获取类路径中的资源文件路径
// JAR 包中,它将返回 null
// String resourcePath = GetResourcePathExample.class.getClassLoader().getResource("example.txt").getPath();
this.getFilePath();
// RTSP 输入 URL 和 HLS 输出设置
String rtspUrl = "rtsp://your_rtsp_stream_url";
rtspUrl = url;
/*
url: "rtsp://用户名:密码@ip:port/Streaming/Channels/101"; // 密码不能有@
url: "rtsp:ip:port/openUrl/U7p2Rgl // 获取摄像头对应的rtsp地址
*/
//
if (StringUtils.isNotBlank(codeName)) {
int nameIdx = codeName.lastIndexOf("\\");
outputName = codeName;
if (nameIdx != -1) {
outputName = codeName.substring(0, nameIdx);
}
}
String outputPath = filePath.replaceAll("/", "\\\\") + outputName + ".m3u8";
//outputPath = "D:\\apache-tomcat-8\\webapps\\output\\" + outputName + ".m3u8";
// FFmpeg 命令
String[] command = {
"ffmpeg",
"-i", rtspUrl,
"-c:v", "libx264",
"-preset", "fast",
"-crf", "20",
"-c:a", "aac",
"-b:a", "128k",
"-f", "hls",
"-hls_time", "10",
"-hls_list_size", "10",
"-hls_flags", "delete_segments",
outputPath
};
String result = "";
try {
// 创建 ProcessBuilder 实例
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true);
// 启动进程
ffmpegProcess = processBuilder.start();
/*
// 读取并打印 FFmpeg 的输出
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
//reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
System.out.println(reader.readLine());
while ((line = reader.readLine()) != null) {
if (result == "") {
result = "/output/"+outputName+".m3u8";
System.out.println(line);
}
}
*/
result = "/file/"+outputName+".m3u8";
//new Thread(() -> {
String line = "";
File dir = new File(outputPath);
int j = 0;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(ffmpegProcess.getInputStream()))) {
// 生成文件后返回视频路径
while (line != null || dir.exists()) {
line = reader.readLine();
dir = new File(outputPath);
System.out.println("line " + Integer.toString(j) + line);
System.out.println("dire " + Integer.toString(j) + " " + dir.exists());
if (line == null || dir.exists()) break;
j++;
}
if (line != null) return result;
} catch (IOException e) {
e.printStackTrace();
}
//}).start();
// 等待进程结束
int exitCode = ffmpegProcess.waitFor();
result = Integer.toString(exitCode);
System.out.println("FFmpeg exited with code " + exitCode);
ffmpegProcess = null;
outputName = "";
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return result;
}
public String stopFFmpeg() {
// 单进程
String result = "false";
if (ffmpegProcess != null) {
ffmpegProcess.destroy(); // 终止FFmpeg进程
System.out.println("FFmpeg process stopped.");
ffmpegProcess = null;
result = "true";
}
if (outputName != "") {
this.delFileInPath();
outputName = "";
}
return result;
}
/**
* 判断创建文件
* */
public void getFilePath() {
// 创建目录
File dir = new File(filePath);
boolean start = dir.exists();
if (!dir.exists()) {
dir.mkdirs();
start = dir.exists();
}
System.out.println(start);
}
/**
* 删除文件夹下的文件
* */
public void delFileInPath() {
File directory = new File(filePath);
// 检查目录是否存在并且是一个目录
if (directory.exists() && directory.isDirectory()) {
// 获取目录中的所有文件和子目录
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
if (file.isFile()) {
if (outputName != "") {
if (file.getName().indexOf(outputName) != -1) {
file.delete();
}
} else {
System.out.println("文件: " + file.getName());
}
} else if (file.isDirectory()) {
System.out.println("目录: " + file.getName());
}
}
} else {
System.out.println("无法列出目录中的文件");
}
} else {
System.out.println("指定的路径不是一个有效的目录");
}
}
}