mirror of
https://gitee.com/pan648540858/wvp-GB28181-pro.git
synced 2026-06-20 01:57:50 +08:00
Merge branch 'wvp-28181-2.0' into 结构优化
# Conflicts: # sql/2.6.9更新.sql # src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java # src/main/java/com/genersoft/iot/vmp/service/IPlayService.java # src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java # src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java # src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java # src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java # 数据库/old/common.sql
This commit is contained in:
commit
b4fb076246
@ -1,14 +0,0 @@
|
||||
alter table wvp_device_channel
|
||||
change stream_id stream_id varying(255)
|
||||
|
||||
alter table wvp_device_channel
|
||||
add common_gb_channel_id int
|
||||
|
||||
alter table wvp_platform
|
||||
add auto_push_channel bool default false
|
||||
|
||||
alter table wvp_device
|
||||
add auto_sync_channel bool default true
|
||||
|
||||
alter table wvp_stream_proxy
|
||||
add stream_key character varying(255)
|
||||
@ -1,5 +1,6 @@
|
||||
package com.genersoft.iot.vmp.common;
|
||||
|
||||
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -76,6 +77,8 @@ public class StreamInfo implements Serializable, Cloneable{
|
||||
private String endTime;
|
||||
@Schema(description = "进度(录像下载使用)")
|
||||
private double progress;
|
||||
@Schema(description = "文件下载地址(录像下载使用)")
|
||||
private DownloadFileInfo downLoadFilePath;
|
||||
|
||||
@Schema(description = "是否暂停(录像回放使用)")
|
||||
private boolean pause;
|
||||
@ -605,5 +608,11 @@ public class StreamInfo implements Serializable, Cloneable{
|
||||
this.subStream = subStream;
|
||||
}
|
||||
|
||||
public DownloadFileInfo getDownLoadFilePath() {
|
||||
return downLoadFilePath;
|
||||
}
|
||||
|
||||
public void setDownLoadFilePath(DownloadFileInfo downLoadFilePath) {
|
||||
this.downLoadFilePath = downLoadFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ public class VideoManagerConstants {
|
||||
|
||||
public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_MEDIA_TRANSACTION_";
|
||||
|
||||
public static final String MEDIA_STREAM_AUTHORITY = "MEDIA_STREAM_AUTHORITY_";
|
||||
public static final String MEDIA_STREAM_AUTHORITY = "VMP_MEDIA_STREAM_AUTHORITY_";
|
||||
|
||||
public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_";
|
||||
|
||||
@ -70,6 +70,7 @@ public class VideoManagerConstants {
|
||||
public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_";
|
||||
|
||||
public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_";
|
||||
public static final String PUSH_STREAM_LIST = "VMP_PUSH_STREAM_LIST_";
|
||||
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,83 @@
|
||||
package com.genersoft.iot.vmp.conf;
|
||||
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
|
||||
import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper;
|
||||
import com.genersoft.iot.vmp.vmanager.cloudRecord.CloudRecordController;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 录像文件定时删除
|
||||
*/
|
||||
@Component
|
||||
public class CloudRecordTimer {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(CloudRecordTimer.class);
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private CloudRecordServiceMapper cloudRecordServiceMapper;
|
||||
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
/**
|
||||
* 定时查询待删除的录像文件
|
||||
*/
|
||||
// @Scheduled(fixedRate = 10000) //每五秒执行一次,方便测试
|
||||
@Scheduled(cron = "0 0 0 * * ?") //每天的0点执行
|
||||
public void execute(){
|
||||
logger.info("[录像文件定时清理] 开始清理过期录像文件");
|
||||
// 获取配置了assist的流媒体节点
|
||||
List<MediaServerItem> mediaServerItemList = mediaServerService.getAllOnline();
|
||||
if (mediaServerItemList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
long result = 0;
|
||||
for (MediaServerItem mediaServerItem : mediaServerItemList) {
|
||||
|
||||
Calendar lastCalendar = Calendar.getInstance();
|
||||
if (mediaServerItem.getRecordDay() > 0) {
|
||||
lastCalendar.setTime(new Date());
|
||||
// 获取保存的最后截至日[期,因为每个节点都有一个日期,也就是支持每个节点设置不同的保存日期,
|
||||
lastCalendar.add(Calendar.DAY_OF_MONTH, -mediaServerItem.getRecordDay());
|
||||
Long lastDate = lastCalendar.getTimeInMillis();
|
||||
|
||||
// 获取到截至日期之前的录像文件列表,文件列表满足未被收藏和保持的。这两个字段目前共能一致,
|
||||
// 为我自己业务系统相关的代码,大家使用的时候直接使用收藏(collect)这一个类型即可
|
||||
List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.queryRecordListForDelete(lastDate, mediaServerItem.getId());
|
||||
if (cloudRecordItemList.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
// TODO 后续可以删除空了的过期日期文件夹
|
||||
for (CloudRecordItem cloudRecordItem : cloudRecordItemList) {
|
||||
String date = new File(cloudRecordItem.getFilePath()).getParentFile().getName();
|
||||
JSONObject jsonObject = zlmresTfulUtils.deleteRecordDirectory(mediaServerItem, cloudRecordItem.getApp(),
|
||||
cloudRecordItem.getStream(), date, cloudRecordItem.getFileName());
|
||||
if (jsonObject.getInteger("code") != 0) {
|
||||
logger.warn("[录像文件定时清理] 删除磁盘文件错误: {}:{}", cloudRecordItem.getFilePath(), jsonObject);
|
||||
}
|
||||
}
|
||||
result += cloudRecordServiceMapper.deleteList(cloudRecordItemList);
|
||||
}
|
||||
}
|
||||
logger.info("[录像文件定时清理] 共清理{}个过期录像文件", result);
|
||||
}
|
||||
}
|
||||
@ -81,6 +81,12 @@ public class MediaConfig{
|
||||
@Value("${media.record-assist-port:0}")
|
||||
private Integer recordAssistPort = 0;
|
||||
|
||||
@Value("${media.record-day:7}")
|
||||
private Integer recordDay;
|
||||
|
||||
@Value("${media.record-path}")
|
||||
private String recordPath;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
@ -212,13 +218,32 @@ public class MediaConfig{
|
||||
mediaServerItem.setSendRtpPortRange(rtpSendPortRange);
|
||||
mediaServerItem.setRecordAssistPort(recordAssistPort);
|
||||
mediaServerItem.setHookAliveInterval(30.00f);
|
||||
|
||||
mediaServerItem.setRecordDay(recordDay);
|
||||
if (recordPath != null) {
|
||||
mediaServerItem.setRecordPath(recordPath);
|
||||
}
|
||||
mediaServerItem.setCreateTime(DateUtil.getNow());
|
||||
mediaServerItem.setUpdateTime(DateUtil.getNow());
|
||||
|
||||
return mediaServerItem;
|
||||
}
|
||||
|
||||
public Integer getRecordDay() {
|
||||
return recordDay;
|
||||
}
|
||||
|
||||
public void setRecordDay(Integer recordDay) {
|
||||
this.recordDay = recordDay;
|
||||
}
|
||||
|
||||
public String getRecordPath() {
|
||||
return recordPath;
|
||||
}
|
||||
|
||||
public void setRecordPath(String recordPath) {
|
||||
this.recordPath = recordPath;
|
||||
}
|
||||
|
||||
public String getRtpSendPortRange() {
|
||||
return rtpSendPortRange;
|
||||
}
|
||||
|
||||
@ -39,4 +39,6 @@ public class SystemInfoTimerTask {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -56,8 +56,6 @@ public class UserSetting {
|
||||
|
||||
private String serverId = "000000";
|
||||
|
||||
private String recordPath = null;
|
||||
|
||||
private String thirdPartyGBIdReg = "[\\s\\S]*";
|
||||
|
||||
private String civilCodeFile = "classpath:civilCode.csv";
|
||||
@ -252,14 +250,6 @@ public class UserSetting {
|
||||
this.refuseChannelStatusChannelFormNotify = refuseChannelStatusChannelFormNotify;
|
||||
}
|
||||
|
||||
public String getRecordPath() {
|
||||
return recordPath;
|
||||
}
|
||||
|
||||
public void setRecordPath(String recordPath) {
|
||||
this.recordPath = recordPath;
|
||||
}
|
||||
|
||||
public int getMaxNotifyCountQueue() {
|
||||
return maxNotifyCountQueue;
|
||||
}
|
||||
|
||||
@ -75,6 +75,33 @@ public class VideoStreamSessionManager {
|
||||
return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0));
|
||||
}
|
||||
|
||||
public SsrcTransaction getSsrcTransactionByCallId(String callId){
|
||||
|
||||
if (ObjectUtils.isEmpty(callId)) {
|
||||
return null;
|
||||
}
|
||||
String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_*_*_" + callId+ "_*";
|
||||
List<Object> scanResult = RedisUtil.scan(redisTemplate, key);
|
||||
if (!scanResult.isEmpty()) {
|
||||
return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0));
|
||||
}else {
|
||||
key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_*_*_play_*";
|
||||
scanResult = RedisUtil.scan(redisTemplate, key);
|
||||
if (scanResult.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
for (Object keyObj : scanResult) {
|
||||
SsrcTransaction ssrcTransaction = (SsrcTransaction)redisTemplate.opsForValue().get(keyObj);
|
||||
if (ssrcTransaction.getSipTransactionInfo() != null &&
|
||||
ssrcTransaction.getSipTransactionInfo().getCallId().equals(callId)) {
|
||||
return ssrcTransaction;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public List<SsrcTransaction> getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream){
|
||||
if (ObjectUtils.isEmpty(deviceId)) {
|
||||
deviceId ="*";
|
||||
|
||||
@ -129,4 +129,6 @@ public class SipRunner implements CommandLineRunner {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@ import javax.sip.header.CallIdHeader;
|
||||
import javax.sip.message.Response;
|
||||
import java.text.ParseException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -149,7 +150,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In
|
||||
}else {
|
||||
|
||||
// 可能是设备发送的停止
|
||||
SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(null, null, callIdHeader.getCallId(), null);
|
||||
SsrcTransaction ssrcTransaction = streamSession.getSsrcTransactionByCallId(callIdHeader.getCallId());
|
||||
if (ssrcTransaction == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -141,7 +141,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
|
||||
String requesterId = SipUtils.getUserIdFromFromHeader(request);
|
||||
CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME);
|
||||
if (requesterId == null || channelId == null) {
|
||||
logger.info("无法从FromHeader的Address中获取到平台id,返回400");
|
||||
logger.info("无法从请求中获取到平台id,返回400");
|
||||
// 参数不全, 发400,请求错误
|
||||
try {
|
||||
responseAck(request, Response.BAD_REQUEST);
|
||||
|
||||
@ -76,7 +76,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
|
||||
|
||||
RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress());
|
||||
if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) {
|
||||
logger.info("[心跳] 设备{}地址变化, 远程地址为: {}:{}", device.getDeviceId(), remoteAddressInfo.getIp(), remoteAddressInfo.getPort());
|
||||
logger.info("[收到心跳] 设备{}地址变化, 远程地址为: {}:{}", device.getDeviceId(), remoteAddressInfo.getIp(), remoteAddressInfo.getPort());
|
||||
device.setPort(remoteAddressInfo.getPort());
|
||||
device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort())));
|
||||
device.setIp(remoteAddressInfo.getIp());
|
||||
|
||||
@ -9,12 +9,16 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Component
|
||||
public class AssistRESTfulUtils {
|
||||
@ -22,21 +26,41 @@ public class AssistRESTfulUtils {
|
||||
private final static Logger logger = LoggerFactory.getLogger(AssistRESTfulUtils.class);
|
||||
|
||||
|
||||
private OkHttpClient client;
|
||||
|
||||
|
||||
public interface RequestCallback{
|
||||
void run(JSONObject response);
|
||||
}
|
||||
|
||||
private OkHttpClient getClient(){
|
||||
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
|
||||
if (logger.isDebugEnabled()) {
|
||||
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> {
|
||||
logger.debug("http请求参数:" + message);
|
||||
});
|
||||
logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
|
||||
// OkHttp進行添加攔截器loggingInterceptor
|
||||
httpClientBuilder.addInterceptor(logging);
|
||||
return getClient(null);
|
||||
}
|
||||
|
||||
private OkHttpClient getClient(Integer readTimeOut){
|
||||
if (client == null) {
|
||||
if (readTimeOut == null) {
|
||||
readTimeOut = 10;
|
||||
}
|
||||
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
|
||||
// 设置连接超时时间
|
||||
httpClientBuilder.connectTimeout(8, TimeUnit.SECONDS);
|
||||
// 设置读取超时时间
|
||||
httpClientBuilder.readTimeout(readTimeOut,TimeUnit.SECONDS);
|
||||
// 设置连接池
|
||||
httpClientBuilder.connectionPool(new ConnectionPool(16, 5, TimeUnit.MINUTES));
|
||||
if (logger.isDebugEnabled()) {
|
||||
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> {
|
||||
logger.debug("http请求参数:" + message);
|
||||
});
|
||||
logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
|
||||
// OkHttp進行添加攔截器loggingInterceptor
|
||||
httpClientBuilder.addInterceptor(logging);
|
||||
}
|
||||
client = httpClientBuilder.build();
|
||||
}
|
||||
return httpClientBuilder.build();
|
||||
return client;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -124,13 +148,91 @@ public class AssistRESTfulUtils {
|
||||
return responseJSON;
|
||||
}
|
||||
|
||||
public JSONObject sendPost(MediaServerItem mediaServerItem, String api, JSONObject param, ZLMRESTfulUtils.RequestCallback callback, Integer readTimeOut) {
|
||||
OkHttpClient client = getClient(readTimeOut);
|
||||
|
||||
public JSONObject fileDuration(MediaServerItem mediaServerItem, String app, String stream, RequestCallback callback){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("app",app);
|
||||
param.put("stream",stream);
|
||||
param.put("recordIng",true);
|
||||
return sendGet(mediaServerItem, "api/record/file/duration",param, callback);
|
||||
if (mediaServerItem == null) {
|
||||
return null;
|
||||
}
|
||||
String url = String.format("http://%s:%s/%s", mediaServerItem.getIp(), mediaServerItem.getRecordAssistPort(), api);
|
||||
JSONObject responseJSON = new JSONObject();
|
||||
//-2自定义流媒体 调用错误码
|
||||
responseJSON.put("code",-2);
|
||||
responseJSON.put("msg","ASSIST调用失败");
|
||||
|
||||
RequestBody requestBodyJson = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), param.toString());
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.post(requestBodyJson)
|
||||
.url(url)
|
||||
.addHeader("Content-Type", "application/json")
|
||||
.build();
|
||||
if (callback == null) {
|
||||
try {
|
||||
Response response = client.newCall(request).execute();
|
||||
if (response.isSuccessful()) {
|
||||
ResponseBody responseBody = response.body();
|
||||
if (responseBody != null) {
|
||||
String responseStr = responseBody.string();
|
||||
responseJSON = JSON.parseObject(responseStr);
|
||||
}
|
||||
}else {
|
||||
response.close();
|
||||
Objects.requireNonNull(response.body()).close();
|
||||
}
|
||||
}catch (IOException e) {
|
||||
logger.error(String.format("[ %s ]ASSIST请求失败: %s", url, e.getMessage()));
|
||||
|
||||
if(e instanceof SocketTimeoutException){
|
||||
//读取超时超时异常
|
||||
logger.error(String.format("读取ASSIST数据失败: %s, %s", url, e.getMessage()));
|
||||
}
|
||||
if(e instanceof ConnectException){
|
||||
//判断连接异常,我这里是报Failed to connect to 10.7.5.144
|
||||
logger.error(String.format("连接ASSIST失败: %s, %s", url, e.getMessage()));
|
||||
}
|
||||
|
||||
}catch (Exception e){
|
||||
logger.error(String.format("访问ASSIST失败: %s, %s", url, e.getMessage()));
|
||||
}
|
||||
}else {
|
||||
client.newCall(request).enqueue(new Callback(){
|
||||
|
||||
@Override
|
||||
public void onResponse(@NotNull Call call, @NotNull Response response){
|
||||
if (response.isSuccessful()) {
|
||||
try {
|
||||
String responseStr = Objects.requireNonNull(response.body()).string();
|
||||
callback.run(JSON.parseObject(responseStr));
|
||||
} catch (IOException e) {
|
||||
logger.error(String.format("[ %s ]请求失败: %s", url, e.getMessage()));
|
||||
}
|
||||
|
||||
}else {
|
||||
response.close();
|
||||
Objects.requireNonNull(response.body()).close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NotNull Call call, @NotNull IOException e) {
|
||||
logger.error(String.format("连接ZLM失败: %s, %s", call.request().toString(), e.getMessage()));
|
||||
|
||||
if(e instanceof SocketTimeoutException){
|
||||
//读取超时超时异常
|
||||
logger.error(String.format("读取ZLM数据失败: %s, %s", call.request().toString(), e.getMessage()));
|
||||
}
|
||||
if(e instanceof ConnectException){
|
||||
//判断连接异常,我这里是报Failed to connect to 10.7.5.144
|
||||
logger.error(String.format("连接ZLM失败: %s, %s", call.request().toString(), e.getMessage()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
return responseJSON;
|
||||
}
|
||||
|
||||
public JSONObject getInfo(MediaServerItem mediaServerItem, RequestCallback callback){
|
||||
@ -138,33 +240,41 @@ public class AssistRESTfulUtils {
|
||||
return sendGet(mediaServerItem, "api/record/info",param, callback);
|
||||
}
|
||||
|
||||
public JSONObject addStreamCallInfo(MediaServerItem mediaServerItem, String app, String stream, String callId, RequestCallback callback){
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("app",app);
|
||||
param.put("stream",stream);
|
||||
param.put("callId",callId);
|
||||
return sendGet(mediaServerItem, "api/record/addStreamCallInfo",param, callback);
|
||||
public JSONObject addTask(MediaServerItem mediaServerItem, String app, String stream, String startTime,
|
||||
String endTime, String callId, List<String> filePathList, String remoteHost) {
|
||||
|
||||
JSONObject videoTaskInfoJSON = new JSONObject();
|
||||
videoTaskInfoJSON.put("app", app);
|
||||
videoTaskInfoJSON.put("stream", stream);
|
||||
videoTaskInfoJSON.put("startTime", startTime);
|
||||
videoTaskInfoJSON.put("endTime", endTime);
|
||||
videoTaskInfoJSON.put("callId", callId);
|
||||
videoTaskInfoJSON.put("filePathList", filePathList);
|
||||
if (!ObjectUtils.isEmpty(remoteHost)) {
|
||||
videoTaskInfoJSON.put("remoteHost", remoteHost);
|
||||
}
|
||||
|
||||
return sendPost(mediaServerItem, "api/record/file/download/task/add", videoTaskInfoJSON, null, 30);
|
||||
}
|
||||
|
||||
public JSONObject getDateList(MediaServerItem mediaServerItem, String app, String stream, int year, int month) {
|
||||
public JSONObject queryTaskList(MediaServerItem mediaServerItem, String app, String stream, String callId, String taskId, Boolean isEnd) {
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("app", app);
|
||||
param.put("stream", stream);
|
||||
param.put("year", year);
|
||||
param.put("month", month);
|
||||
return sendGet(mediaServerItem, "api/record/date/list", param, null);
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(app)) {
|
||||
param.put("app", app);
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(stream)) {
|
||||
param.put("stream", stream);
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(callId)) {
|
||||
param.put("callId", callId);
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(taskId)) {
|
||||
param.put("taskId", taskId);
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(isEnd)) {
|
||||
param.put("isEnd", isEnd);
|
||||
}
|
||||
|
||||
public JSONObject getFileList(MediaServerItem mediaServerItem, int page, int count, String app, String stream,
|
||||
String startTime, String endTime) {
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("app", app);
|
||||
param.put("stream", stream);
|
||||
param.put("page", page);
|
||||
param.put("count", count);
|
||||
param.put("startTime", startTime);
|
||||
param.put("endTime", endTime);
|
||||
return sendGet(mediaServerItem, "api/record/file/listWithDate", param, null);
|
||||
return sendGet(mediaServerItem, "api/record/file/download/task/list", param, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -107,6 +107,9 @@ public class ZLMHttpHookListener {
|
||||
@Autowired
|
||||
private IUserService userService;
|
||||
|
||||
@Autowired
|
||||
private ICloudRecordService cloudRecordService;
|
||||
|
||||
@Autowired
|
||||
private VideoStreamSessionManager sessionManager;
|
||||
|
||||
@ -228,12 +231,6 @@ public class ZLMHttpHookListener {
|
||||
streamAuthorityInfo.setSign(sign);
|
||||
// 鉴权通过
|
||||
redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);
|
||||
// 通知assist新的callId
|
||||
if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) {
|
||||
taskExecutor.execute(() -> {
|
||||
assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null);
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId());
|
||||
@ -259,7 +256,6 @@ public class ZLMHttpHookListener {
|
||||
} else {
|
||||
result.setEnable_mp4(userSetting.isRecordPushLive());
|
||||
}
|
||||
|
||||
// 国标流
|
||||
if ("rtp".equals(param.getApp()) ) {
|
||||
|
||||
@ -276,9 +272,17 @@ public class ZLMHttpHookListener {
|
||||
}
|
||||
|
||||
// 设置音频信息及录制信息
|
||||
List<SsrcTransaction> ssrcTransactionForAll = (inviteInfo == null ? null :
|
||||
sessionManager.getSsrcTransactionForAll(inviteInfo.getDeviceId(), inviteInfo.getChannelId(), null, null));
|
||||
List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream());
|
||||
if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) {
|
||||
|
||||
// 为录制国标模拟一个鉴权信息, 方便后续写入录像文件时使用
|
||||
StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);
|
||||
streamAuthorityInfo.setApp(param.getApp());
|
||||
streamAuthorityInfo.setStream(ssrcTransactionForAll.get(0).getStream());
|
||||
streamAuthorityInfo.setCallId(ssrcTransactionForAll.get(0).getSipTransactionInfo().getCallId());
|
||||
|
||||
redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), ssrcTransactionForAll.get(0).getStream(), streamAuthorityInfo);
|
||||
|
||||
String deviceId = ssrcTransactionForAll.get(0).getDeviceId();
|
||||
String channelId = ssrcTransactionForAll.get(0).getChannelId();
|
||||
DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
|
||||
@ -287,26 +291,16 @@ public class ZLMHttpHookListener {
|
||||
}
|
||||
// 如果是录像下载就设置视频间隔十秒
|
||||
if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) {
|
||||
result.setMp4_max_second(10);
|
||||
result.setEnable_mp4(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) {
|
||||
logger.info("推流时发现尚未设置录像路径,从assist服务中读取");
|
||||
JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null);
|
||||
if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) {
|
||||
JSONObject dataJson = info.getJSONObject("data");
|
||||
if (dataJson != null) {
|
||||
String recordPath = dataJson.getString("record");
|
||||
userSetting.setRecordPath(recordPath);
|
||||
result.setMp4_save_path(recordPath);
|
||||
// 修改zlm中的录像路径
|
||||
if (mediaInfo.isAutoConfig()) {
|
||||
taskExecutor.execute(() -> {
|
||||
mediaServerService.setZLMConfig(mediaInfo, false);
|
||||
});
|
||||
// 获取录像的总时长,然后设置为这个视频的时长
|
||||
InviteInfo inviteInfoForDownload = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, param.getStream());
|
||||
if (inviteInfoForDownload != null && inviteInfoForDownload.getStreamInfo() != null) {
|
||||
String startTime = inviteInfoForDownload.getStreamInfo().getStartTime();
|
||||
String endTime = inviteInfoForDownload.getStreamInfo().getEndTime();
|
||||
long difference = DateUtil.getDifference(startTime, endTime) / 1000;
|
||||
result.setMp4_max_second((int) difference);
|
||||
result.setEnable_mp4(true);
|
||||
// 设置为2保证得到的mp4的时长是正常的
|
||||
result.setModify_stamp(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -354,13 +348,11 @@ public class ZLMHttpHookListener {
|
||||
|
||||
List<StreamMediaTrack> tracks = param.getTracks();
|
||||
// TODO 重构此处逻辑
|
||||
boolean isPush = false;
|
||||
if (param.isRegist()) {
|
||||
// 处理流注册的鉴权信息
|
||||
// 处理流注册的鉴权信息, 流注销这里不再删除鉴权信息,下次来了新的鉴权信息会对就的进行覆盖
|
||||
if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
|
||||
|| param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
|
||||
|| param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {
|
||||
isPush = true;
|
||||
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
|
||||
if (streamAuthorityInfo == null) {
|
||||
streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);
|
||||
@ -370,8 +362,6 @@ public class ZLMHttpHookListener {
|
||||
}
|
||||
redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);
|
||||
}
|
||||
} else {
|
||||
redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream());
|
||||
}
|
||||
|
||||
if ("rtsp".equals(param.getSchema())) {
|
||||
@ -412,6 +402,9 @@ public class ZLMHttpHookListener {
|
||||
|| param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {
|
||||
param.setSeverId(userSetting.getServerId());
|
||||
zlmMediaListManager.addPush(param);
|
||||
|
||||
// 冗余数据,自己系统中自用
|
||||
redisCatchStorage.addPushListItem(param.getApp(), param.getStream(), param);
|
||||
}
|
||||
} else {
|
||||
// 兼容流注销时类型从redis记录获取
|
||||
@ -420,6 +413,10 @@ public class ZLMHttpHookListener {
|
||||
if (onStreamChangedHookParam != null) {
|
||||
type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType();
|
||||
redisCatchStorage.removeStream(mediaInfo.getId(), type, param.getApp(), param.getStream());
|
||||
if ("PUSH".equalsIgnoreCase(type)) {
|
||||
// 冗余数据,自己系统中自用
|
||||
redisCatchStorage.removePushListItem(param.getApp(), param.getStream(), param.getMediaServerId());
|
||||
}
|
||||
}
|
||||
zlmMediaListManager.streamOffline(param.getApp(), param.getStream());
|
||||
}
|
||||
@ -758,7 +755,7 @@ public class ZLMHttpHookListener {
|
||||
taskExecutor.execute(() -> {
|
||||
JSONObject json = (JSONObject) JSON.toJSON(param);
|
||||
List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout);
|
||||
if (subscribes != null && subscribes.size() > 0) {
|
||||
if (subscribes != null && !subscribes.isEmpty()) {
|
||||
for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|
||||
subscribe.response(null, param);
|
||||
}
|
||||
@ -768,6 +765,28 @@ public class ZLMHttpHookListener {
|
||||
return HookResult.SUCCESS();
|
||||
}
|
||||
|
||||
/**
|
||||
* 录像完成事件
|
||||
*/
|
||||
@ResponseBody
|
||||
@PostMapping(value = "/on_record_mp4", produces = "application/json;charset=UTF-8")
|
||||
public HookResult onRecordMp4(HttpServletRequest request, @RequestBody OnRecordMp4HookParam param) {
|
||||
logger.info("[ZLM HOOK] 录像完成事件:{}->{}", param.getMediaServerId(), param.getFile_path());
|
||||
|
||||
taskExecutor.execute(() -> {
|
||||
List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_record_mp4);
|
||||
if (subscribes != null && !subscribes.isEmpty()) {
|
||||
for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
|
||||
subscribe.response(null, param);
|
||||
}
|
||||
}
|
||||
cloudRecordService.addRecord(param);
|
||||
|
||||
});
|
||||
|
||||
return HookResult.SUCCESS();
|
||||
}
|
||||
|
||||
private Map<String, String> urlParamToMap(String params) {
|
||||
HashMap<String, String> map = new HashMap<>();
|
||||
if (ObjectUtils.isEmpty(params)) {
|
||||
|
||||
@ -25,8 +25,6 @@ public class ZLMRESTfulUtils {
|
||||
|
||||
private OkHttpClient client;
|
||||
|
||||
|
||||
|
||||
public interface RequestCallback{
|
||||
void run(JSONObject response);
|
||||
}
|
||||
@ -398,4 +396,14 @@ public class ZLMRESTfulUtils {
|
||||
param.put("stream_id", streamId);
|
||||
return sendPost(mediaServerItem, "updateRtpServerSSRC",param, null);
|
||||
}
|
||||
|
||||
public JSONObject deleteRecordDirectory(MediaServerItem mediaServerItem, String app, String stream, String date, String fileName) {
|
||||
Map<String, Object> param = new HashMap<>(1);
|
||||
param.put("vhost", "__defaultVhost__");
|
||||
param.put("app", app);
|
||||
param.put("stream", stream);
|
||||
param.put("period", date);
|
||||
param.put("name", fileName);
|
||||
return sendPost(mediaServerItem, "deleteRecordDirectory",param, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,4 +41,15 @@ public class HookSubscribeFactory {
|
||||
|
||||
return hookSubscribe;
|
||||
}
|
||||
|
||||
public static HookSubscribeForRecordMp4 on_record_mp4(String mediaServerId, String app, String stream) {
|
||||
HookSubscribeForRecordMp4 hookSubscribe = new HookSubscribeForRecordMp4();
|
||||
JSONObject subscribeKey = new com.alibaba.fastjson2.JSONObject();
|
||||
subscribeKey.put("app", app);
|
||||
subscribeKey.put("stream", stream);
|
||||
subscribeKey.put("mediaServerId", mediaServerId);
|
||||
hookSubscribe.setContent(subscribeKey);
|
||||
|
||||
return hookSubscribe;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
package com.genersoft.iot.vmp.media.zlm.dto;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* hook订阅-录像完成
|
||||
* @author lin
|
||||
*/
|
||||
public class HookSubscribeForRecordMp4 implements IHookSubscribe{
|
||||
|
||||
private HookType hookType = HookType.on_record_mp4;
|
||||
|
||||
private JSONObject content;
|
||||
|
||||
@JSONField(format="yyyy-MM-dd HH:mm:ss")
|
||||
private Instant expires;
|
||||
|
||||
@Override
|
||||
public HookType getHookType() {
|
||||
return hookType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(JSONObject content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant getExpires() {
|
||||
return expires;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpires(Instant expires) {
|
||||
this.expires = expires;
|
||||
}
|
||||
}
|
||||
@ -80,9 +80,11 @@ public class MediaServerItem{
|
||||
@Schema(description = "是否是默认ZLM")
|
||||
private boolean defaultServer;
|
||||
|
||||
@Schema(description = "当前使用到的端口")
|
||||
private int currentPort;
|
||||
@Schema(description = "录像存储时长")
|
||||
private int recordDay;
|
||||
|
||||
@Schema(description = "录像存储路径")
|
||||
private String recordPath;
|
||||
|
||||
public MediaServerItem() {
|
||||
}
|
||||
@ -269,14 +271,6 @@ public class MediaServerItem{
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
|
||||
public int getCurrentPort() {
|
||||
return currentPort;
|
||||
}
|
||||
|
||||
public void setCurrentPort(int currentPort) {
|
||||
this.currentPort = currentPort;
|
||||
}
|
||||
|
||||
public boolean isStatus() {
|
||||
return status;
|
||||
}
|
||||
@ -308,4 +302,20 @@ public class MediaServerItem{
|
||||
public void setSendRtpPortRange(String sendRtpPortRange) {
|
||||
this.sendRtpPortRange = sendRtpPortRange;
|
||||
}
|
||||
|
||||
public int getRecordDay() {
|
||||
return recordDay;
|
||||
}
|
||||
|
||||
public void setRecordDay(int recordDay) {
|
||||
this.recordDay = recordDay;
|
||||
}
|
||||
|
||||
public String getRecordPath() {
|
||||
return recordPath;
|
||||
}
|
||||
|
||||
public void setRecordPath(String recordPath) {
|
||||
this.recordPath = recordPath;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ public class HookResultForOnPublish extends HookResult{
|
||||
private int mp4_max_second;
|
||||
private String mp4_save_path;
|
||||
private String stream_replace;
|
||||
private Integer modify_stamp;
|
||||
|
||||
public HookResultForOnPublish() {
|
||||
}
|
||||
@ -60,14 +61,23 @@ public class HookResultForOnPublish extends HookResult{
|
||||
this.stream_replace = stream_replace;
|
||||
}
|
||||
|
||||
public Integer getModify_stamp() {
|
||||
return modify_stamp;
|
||||
}
|
||||
|
||||
public void setModify_stamp(Integer modify_stamp) {
|
||||
this.modify_stamp = modify_stamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HookResultForOnPublish{" +
|
||||
"enable_audio=" + enable_audio +
|
||||
", enable_mp4=" + enable_mp4 +
|
||||
", mp4_max_second=" + mp4_max_second +
|
||||
", stream_replace=" + stream_replace +
|
||||
", mp4_save_path='" + mp4_save_path + '\'' +
|
||||
", stream_replace='" + stream_replace + '\'' +
|
||||
", modify_stamp='" + modify_stamp + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
114
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRecordMp4HookParam.java
Executable file
114
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRecordMp4HookParam.java
Executable file
@ -0,0 +1,114 @@
|
||||
package com.genersoft.iot.vmp.media.zlm.dto.hook;
|
||||
|
||||
/**
|
||||
* zlm hook事件中的on_rtp_server_timeout事件的参数
|
||||
* @author lin
|
||||
*/
|
||||
public class OnRecordMp4HookParam extends HookParam{
|
||||
private String app;
|
||||
private String stream;
|
||||
private String file_name;
|
||||
private String file_path;
|
||||
private long file_size;
|
||||
private String folder;
|
||||
private String url;
|
||||
private String vhost;
|
||||
private long start_time;
|
||||
private double time_len;
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public String getStream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
public void setStream(String stream) {
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public String getFile_name() {
|
||||
return file_name;
|
||||
}
|
||||
|
||||
public void setFile_name(String file_name) {
|
||||
this.file_name = file_name;
|
||||
}
|
||||
|
||||
public String getFile_path() {
|
||||
return file_path;
|
||||
}
|
||||
|
||||
public void setFile_path(String file_path) {
|
||||
this.file_path = file_path;
|
||||
}
|
||||
|
||||
public long getFile_size() {
|
||||
return file_size;
|
||||
}
|
||||
|
||||
public void setFile_size(long file_size) {
|
||||
this.file_size = file_size;
|
||||
}
|
||||
|
||||
public String getFolder() {
|
||||
return folder;
|
||||
}
|
||||
|
||||
public void setFolder(String folder) {
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getVhost() {
|
||||
return vhost;
|
||||
}
|
||||
|
||||
public void setVhost(String vhost) {
|
||||
this.vhost = vhost;
|
||||
}
|
||||
|
||||
public long getStart_time() {
|
||||
return start_time;
|
||||
}
|
||||
|
||||
public void setStart_time(long start_time) {
|
||||
this.start_time = start_time;
|
||||
}
|
||||
|
||||
public double getTime_len() {
|
||||
return time_len;
|
||||
}
|
||||
|
||||
public void setTime_len(double time_len) {
|
||||
this.time_len = time_len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OnRecordMp4HookParam{" +
|
||||
"app='" + app + '\'' +
|
||||
", stream='" + stream + '\'' +
|
||||
", file_name='" + file_name + '\'' +
|
||||
", file_path='" + file_path + '\'' +
|
||||
", file_size='" + file_size + '\'' +
|
||||
", folder='" + folder + '\'' +
|
||||
", url='" + url + '\'' +
|
||||
", vhost='" + vhost + '\'' +
|
||||
", start_time=" + start_time +
|
||||
", time_len=" + time_len +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
58
src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java
Executable file
58
src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java
Executable file
@ -0,0 +1,58 @@
|
||||
package com.genersoft.iot.vmp.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
|
||||
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
|
||||
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 云端录像管理
|
||||
* @author lin
|
||||
*/
|
||||
public interface ICloudRecordService {
|
||||
|
||||
/**
|
||||
* 分页回去云端录像列表
|
||||
*/
|
||||
PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems);
|
||||
|
||||
/**
|
||||
* 根据hook消息增加一条记录
|
||||
*/
|
||||
void addRecord(OnRecordMp4HookParam param);
|
||||
|
||||
/**
|
||||
* 获取所有的日期
|
||||
*/
|
||||
List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems);
|
||||
|
||||
/**
|
||||
* 添加合并任务
|
||||
*/
|
||||
String addTask(String app, String stream, String mediaServerId, String startTime, String endTime, String callId, String remoteHost);
|
||||
|
||||
|
||||
/**
|
||||
* 查询合并任务列表
|
||||
*/
|
||||
JSONArray queryTask(String app, String stream, String callId, String taskId, String mediaServerId, Boolean isEnd);
|
||||
|
||||
/**
|
||||
* 收藏视频,收藏的视频过期不会删除
|
||||
*/
|
||||
int changeCollect(boolean result, String app, String stream, String mediaServerId, String startTime, String endTime, String callId);
|
||||
|
||||
/**
|
||||
* 添加指定录像收藏
|
||||
*/
|
||||
int changeCollectById(Integer recordId, boolean result);
|
||||
|
||||
/**
|
||||
* 获取播放地址
|
||||
*/
|
||||
DownloadFileInfo getPlayUrlPath(Integer recordId);
|
||||
}
|
||||
@ -88,18 +88,13 @@ public interface IMediaServerService {
|
||||
|
||||
void updateMediaServerKeepalive(String mediaServerId, ServerKeepaliveData data);
|
||||
|
||||
boolean checkRtpServer(MediaServerItem mediaServerItem, String rtp, String stream);
|
||||
|
||||
/**
|
||||
* 获取负载信息
|
||||
* @return
|
||||
*/
|
||||
MediaServerLoad getLoad(MediaServerItem mediaServerItem);
|
||||
|
||||
/**
|
||||
* 按时间查找录像文件
|
||||
*/
|
||||
List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems);
|
||||
List<MediaServerItem> getAllWithAssistPort();
|
||||
|
||||
/**
|
||||
* 查找存在录像文件的时间
|
||||
|
||||
@ -22,11 +22,6 @@ public interface IPlayService {
|
||||
|
||||
MediaServerItem getNewMediaServerItem(Device device);
|
||||
|
||||
/**
|
||||
* 获取包含assist服务的节点
|
||||
*/
|
||||
MediaServerItem getNewMediaServerItemHasAssist(Device device);
|
||||
|
||||
void playBack(String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
|
||||
void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback);
|
||||
void zlmServerOffline(String mediaServerId);
|
||||
|
||||
@ -0,0 +1,205 @@
|
||||
package com.genersoft.iot.vmp.service.bean;
|
||||
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
|
||||
|
||||
/**
|
||||
* 云端录像数据
|
||||
*/
|
||||
public class CloudRecordItem {
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
private int id;
|
||||
|
||||
/**
|
||||
* 应用名
|
||||
*/
|
||||
private String app;
|
||||
|
||||
/**
|
||||
* 流
|
||||
*/
|
||||
private String stream;
|
||||
|
||||
/**
|
||||
* 健全ID
|
||||
*/
|
||||
private String callId;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
private long startTime;
|
||||
|
||||
/**
|
||||
* 结束时间
|
||||
*/
|
||||
private long endTime;
|
||||
|
||||
/**
|
||||
* ZLM Id
|
||||
*/
|
||||
private String mediaServerId;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
private String fileName;
|
||||
|
||||
/**
|
||||
* 文件路径
|
||||
*/
|
||||
private String filePath;
|
||||
|
||||
/**
|
||||
* 文件夹
|
||||
*/
|
||||
private String folder;
|
||||
|
||||
/**
|
||||
* 收藏,收藏的文件不移除
|
||||
*/
|
||||
private Boolean collect;
|
||||
|
||||
/**
|
||||
* 保留,收藏的文件不移除
|
||||
*/
|
||||
private Boolean reserve;
|
||||
|
||||
/**
|
||||
* 文件大小
|
||||
*/
|
||||
private long fileSize;
|
||||
|
||||
/**
|
||||
* 文件时长
|
||||
*/
|
||||
private long timeLen;
|
||||
|
||||
public static CloudRecordItem getInstance(OnRecordMp4HookParam param) {
|
||||
CloudRecordItem cloudRecordItem = new CloudRecordItem();
|
||||
cloudRecordItem.setApp(param.getApp());
|
||||
cloudRecordItem.setStream(param.getStream());
|
||||
cloudRecordItem.setStartTime(param.getStart_time()*1000);
|
||||
cloudRecordItem.setFileName(param.getFile_name());
|
||||
cloudRecordItem.setFolder(param.getFolder());
|
||||
cloudRecordItem.setFileSize(param.getFile_size());
|
||||
cloudRecordItem.setFilePath(param.getFile_path());
|
||||
cloudRecordItem.setMediaServerId(param.getMediaServerId());
|
||||
cloudRecordItem.setTimeLen((long) param.getTime_len() * 1000);
|
||||
cloudRecordItem.setEndTime((param.getStart_time() + (long)param.getTime_len()) * 1000);
|
||||
return cloudRecordItem;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
return app;
|
||||
}
|
||||
|
||||
public void setApp(String app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
public String getStream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
public void setStream(String stream) {
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
public String getCallId() {
|
||||
return callId;
|
||||
}
|
||||
|
||||
public void setCallId(String callId) {
|
||||
this.callId = callId;
|
||||
}
|
||||
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(long startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public long getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setEndTime(long endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public String getMediaServerId() {
|
||||
return mediaServerId;
|
||||
}
|
||||
|
||||
public void setMediaServerId(String mediaServerId) {
|
||||
this.mediaServerId = mediaServerId;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public String getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public void setFilePath(String filePath) {
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
public String getFolder() {
|
||||
return folder;
|
||||
}
|
||||
|
||||
public void setFolder(String folder) {
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
public long getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public void setFileSize(long fileSize) {
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
|
||||
public long getTimeLen() {
|
||||
return timeLen;
|
||||
}
|
||||
|
||||
public void setTimeLen(long timeLen) {
|
||||
this.timeLen = timeLen;
|
||||
}
|
||||
|
||||
public Boolean getCollect() {
|
||||
return collect;
|
||||
}
|
||||
|
||||
public void setCollect(Boolean collect) {
|
||||
this.collect = collect;
|
||||
}
|
||||
|
||||
public Boolean getReserve() {
|
||||
return reserve;
|
||||
}
|
||||
|
||||
public void setReserve(Boolean reserve) {
|
||||
this.reserve = reserve;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package com.genersoft.iot.vmp.service.bean;
|
||||
|
||||
public class DownloadFileInfo {
|
||||
|
||||
private String httpPath;
|
||||
private String httpsPath;
|
||||
private String httpDomainPath;
|
||||
private String httpsDomainPath;
|
||||
|
||||
public String getHttpPath() {
|
||||
return httpPath;
|
||||
}
|
||||
|
||||
public void setHttpPath(String httpPath) {
|
||||
this.httpPath = httpPath;
|
||||
}
|
||||
|
||||
public String getHttpsPath() {
|
||||
return httpsPath;
|
||||
}
|
||||
|
||||
public void setHttpsPath(String httpsPath) {
|
||||
this.httpsPath = httpsPath;
|
||||
}
|
||||
|
||||
public String getHttpDomainPath() {
|
||||
return httpDomainPath;
|
||||
}
|
||||
|
||||
public void setHttpDomainPath(String httpDomainPath) {
|
||||
this.httpDomainPath = httpDomainPath;
|
||||
}
|
||||
|
||||
public String getHttpsDomainPath() {
|
||||
return httpsDomainPath;
|
||||
}
|
||||
|
||||
public void setHttpsDomainPath(String httpsDomainPath) {
|
||||
this.httpsDomainPath = httpsDomainPath;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,242 @@
|
||||
package com.genersoft.iot.vmp.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
|
||||
import com.genersoft.iot.vmp.service.ICloudRecordService;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
|
||||
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper;
|
||||
import com.genersoft.iot.vmp.utils.CloudRecordUtils;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
public class CloudRecordServiceImpl implements ICloudRecordService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(CloudRecordServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private CloudRecordServiceMapper cloudRecordServiceMapper;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private IRedisCatchStorage redisCatchStorage;
|
||||
|
||||
@Autowired
|
||||
private AssistRESTfulUtils assistRESTfulUtils;
|
||||
|
||||
@Autowired
|
||||
private VideoStreamSessionManager streamSession;
|
||||
|
||||
@Override
|
||||
public PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) {
|
||||
// 开始时间和结束时间在数据库中都是以秒为单位的
|
||||
Long startTimeStamp = null;
|
||||
Long endTimeStamp = null;
|
||||
if (startTime != null ) {
|
||||
if (!DateUtil.verification(startTime, DateUtil.formatter)) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "开始时间格式错误,正确格式为: " + DateUtil.formatter);
|
||||
}
|
||||
startTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime);
|
||||
|
||||
}
|
||||
if (endTime != null ) {
|
||||
if (!DateUtil.verification(endTime, DateUtil.formatter)) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "结束时间格式错误,正确格式为: " + DateUtil.formatter);
|
||||
}
|
||||
endTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
|
||||
|
||||
}
|
||||
PageHelper.startPage(page, count);
|
||||
List<CloudRecordItem> all = cloudRecordServiceMapper.getList(query, app, stream, startTimeStamp, endTimeStamp,
|
||||
null, mediaServerItems);
|
||||
return new PageInfo<>(all);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems) {
|
||||
LocalDate startDate = LocalDate.of(year, month, 1);
|
||||
LocalDate endDate;
|
||||
if (month == 12) {
|
||||
endDate = LocalDate.of(year + 1, 1, 1);
|
||||
}else {
|
||||
endDate = LocalDate.of(year, month + 1, 1);
|
||||
}
|
||||
long startTimeStamp = startDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond();
|
||||
long endTimeStamp = endDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond();
|
||||
List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getList(null, app, stream, startTimeStamp,
|
||||
endTimeStamp, null, mediaServerItems);
|
||||
if (cloudRecordItemList.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Set<String> resultSet = new HashSet<>();
|
||||
cloudRecordItemList.stream().forEach(cloudRecordItem -> {
|
||||
String date = DateUtil.timestampTo_yyyy_MM_dd(cloudRecordItem.getStartTime());
|
||||
resultSet.add(date);
|
||||
});
|
||||
return new ArrayList<>(resultSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRecord(OnRecordMp4HookParam param) {
|
||||
CloudRecordItem cloudRecordItem = CloudRecordItem.getInstance(param);
|
||||
StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
|
||||
if (streamAuthorityInfo != null) {
|
||||
cloudRecordItem.setCallId(streamAuthorityInfo.getCallId());
|
||||
}
|
||||
logger.info("[添加录像记录] {}/{} 文件大小:{}, 时长: {}秒", param.getApp(), param.getStream(), param.getFile_size(),param.getTime_len());
|
||||
cloudRecordServiceMapper.add(cloudRecordItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String addTask(String app, String stream, String mediaServerId, String startTime, String endTime, String callId, String remoteHost) {
|
||||
// 参数校验
|
||||
assert app != null;
|
||||
assert stream != null;
|
||||
MediaServerItem mediaServerItem = null;
|
||||
if (mediaServerId == null) {
|
||||
mediaServerItem = mediaServerService.getDefaultMediaServer();
|
||||
}else {
|
||||
mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
}
|
||||
if (mediaServerItem == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的流媒体");
|
||||
}else {
|
||||
if (remoteHost == null) {
|
||||
remoteHost = "http://" + mediaServerItem.getStreamIp() + ":" + mediaServerItem.getRecordAssistPort();
|
||||
}
|
||||
}
|
||||
if (mediaServerItem.getRecordAssistPort() == 0) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "为配置Assist服务");
|
||||
}
|
||||
Long startTimeStamp = null;
|
||||
Long endTimeStamp = null;
|
||||
if (startTime != null) {
|
||||
startTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime);
|
||||
}
|
||||
if (endTime != null) {
|
||||
endTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
|
||||
}
|
||||
|
||||
List<MediaServerItem> mediaServers = new ArrayList<>();
|
||||
mediaServers.add(mediaServerItem);
|
||||
// 检索相关的录像文件
|
||||
List<String> filePathList = cloudRecordServiceMapper.queryRecordFilePathList(app, stream, startTimeStamp, endTimeStamp, callId, mediaServers);
|
||||
if (filePathList == null || filePathList.isEmpty()) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未检索到视频文件");
|
||||
}
|
||||
JSONObject result = assistRESTfulUtils.addTask(mediaServerItem, app, stream, startTime, endTime, callId, filePathList, remoteHost);
|
||||
if (result.getInteger("code") != 0) {
|
||||
throw new ControllerException(result.getInteger("code"), result.getString("msg"));
|
||||
}
|
||||
return result.getString("data");
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONArray queryTask(String app, String stream, String callId, String taskId, String mediaServerId, Boolean isEnd) {
|
||||
MediaServerItem mediaServerItem = null;
|
||||
if (mediaServerId == null) {
|
||||
mediaServerItem = mediaServerService.getDefaultMediaServer();
|
||||
}else {
|
||||
mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
}
|
||||
if (mediaServerItem == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的流媒体");
|
||||
}
|
||||
JSONObject result = assistRESTfulUtils.queryTaskList(mediaServerItem, app, stream, callId, taskId, isEnd);
|
||||
if (result.getInteger("code") != 0) {
|
||||
throw new ControllerException(result.getInteger("code"), result.getString("msg"));
|
||||
}
|
||||
return result.getJSONArray("data");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int changeCollect(boolean result, String app, String stream, String mediaServerId, String startTime, String endTime, String callId) {
|
||||
// 开始时间和结束时间在数据库中都是以秒为单位的
|
||||
Long startTimeStamp = null;
|
||||
Long endTimeStamp = null;
|
||||
if (startTime != null ) {
|
||||
if (!DateUtil.verification(startTime, DateUtil.formatter)) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "开始时间格式错误,正确格式为: " + DateUtil.formatter);
|
||||
}
|
||||
startTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime);
|
||||
|
||||
}
|
||||
if (endTime != null ) {
|
||||
if (!DateUtil.verification(endTime, DateUtil.formatter)) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "结束时间格式错误,正确格式为: " + DateUtil.formatter);
|
||||
}
|
||||
endTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
|
||||
|
||||
}
|
||||
|
||||
List<MediaServerItem> mediaServerItems;
|
||||
if (!ObjectUtils.isEmpty(mediaServerId)) {
|
||||
mediaServerItems = new ArrayList<>();
|
||||
MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaServerItem == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到流媒体: " + mediaServerId);
|
||||
}
|
||||
mediaServerItems.add(mediaServerItem);
|
||||
} else {
|
||||
mediaServerItems = null;
|
||||
}
|
||||
|
||||
List<CloudRecordItem> all = cloudRecordServiceMapper.getList(null, app, stream, startTimeStamp, endTimeStamp,
|
||||
callId, mediaServerItems);
|
||||
if (all.isEmpty()) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到待收藏的视频");
|
||||
}
|
||||
int limitCount = 50;
|
||||
int resultCount = 0;
|
||||
if (all.size() > limitCount) {
|
||||
for (int i = 0; i < all.size(); i += limitCount) {
|
||||
int toIndex = i + limitCount;
|
||||
if (i + limitCount > all.size()) {
|
||||
toIndex = all.size();
|
||||
}
|
||||
resultCount += cloudRecordServiceMapper.updateCollectList(result, all.subList(i, toIndex));
|
||||
|
||||
}
|
||||
}else {
|
||||
resultCount = cloudRecordServiceMapper.updateCollectList(result, all);
|
||||
}
|
||||
return resultCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int changeCollectById(Integer recordId, boolean result) {
|
||||
return cloudRecordServiceMapper.changeCollectById(result, recordId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DownloadFileInfo getPlayUrlPath(Integer recordId) {
|
||||
CloudRecordItem recordItem = cloudRecordServiceMapper.queryOne(recordId);
|
||||
if (recordItem == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR400.getCode(), "资源不存在");
|
||||
}
|
||||
String filePath = recordItem.getFilePath();
|
||||
MediaServerItem mediaServerItem = mediaServerService.getOne(recordItem.getMediaServerId());
|
||||
return CloudRecordUtils.getDownloadFilePath(mediaServerItem, filePath);
|
||||
}
|
||||
}
|
||||
@ -159,32 +159,35 @@ public class DeviceServiceImpl implements IDeviceService {
|
||||
commonGbChannelService.onlineForList(ids);
|
||||
}
|
||||
}
|
||||
// 上线添加订阅
|
||||
if (device.getSubscribeCycleForCatalog() > 0) {
|
||||
// 查询在线设备那些开启了订阅,为设备开启定时的目录订阅
|
||||
addCatalogSubscribe(device);
|
||||
}
|
||||
if (device.getSubscribeCycleForMobilePosition() > 0) {
|
||||
addMobilePositionSubscribe(device);
|
||||
}
|
||||
if (userSetting.getDeviceStatusNotify()) {
|
||||
// 发送redis消息
|
||||
redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, true);
|
||||
}
|
||||
|
||||
}else {
|
||||
if (deviceChannelMapper.queryAllChannels(device.getDeviceId()).size() == 0) {
|
||||
logger.info("[设备上线]: {},通道数为0,查询通道信息", device.getDeviceId());
|
||||
sync(device);
|
||||
}
|
||||
|
||||
deviceMapper.update(device);
|
||||
redisCatchStorage.updateDevice(device);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 上线添加订阅
|
||||
if (device.getSubscribeCycleForCatalog() > 0) {
|
||||
// 查询在线设备那些开启了订阅,为设备开启定时的目录订阅
|
||||
addCatalogSubscribe(device);
|
||||
}
|
||||
if (device.getSubscribeCycleForMobilePosition() > 0) {
|
||||
addMobilePositionSubscribe(device);
|
||||
}
|
||||
// 刷新过期任务
|
||||
String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId();
|
||||
// 如果第一次注册那么必须在60 * 3时间内收到一个心跳,否则设备离线
|
||||
dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId(), "首次注册后未能收到心跳"), device.getKeepaliveIntervalTime() * 1000 * 3);
|
||||
if (userSetting.getDeviceStatusNotify()) {
|
||||
// 发送redis消息
|
||||
redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, true);
|
||||
}
|
||||
|
||||
//
|
||||
// try {
|
||||
@ -209,11 +212,16 @@ public class DeviceServiceImpl implements IDeviceService {
|
||||
String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + deviceId;
|
||||
dynamicTask.stop(registerExpireTaskKey);
|
||||
if (device.isOnLine()) {
|
||||
if (userSetting.getDeviceStatusNotify()) {
|
||||
// 发送redis消息
|
||||
redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, false);
|
||||
}
|
||||
List<Integer> ids = deviceChannelMapper.getCommonChannelIdList(device.getDeviceId());
|
||||
if (!ids.isEmpty()) {
|
||||
commonGbChannelService.offlineForList(ids);
|
||||
}
|
||||
}
|
||||
|
||||
device.setOnLine(false);
|
||||
redisCatchStorage.updateDevice(device);
|
||||
deviceMapper.update(device);
|
||||
@ -231,11 +239,6 @@ public class DeviceServiceImpl implements IDeviceService {
|
||||
// 移除订阅
|
||||
removeCatalogSubscribe(device);
|
||||
removeMobilePositionSubscribe(device);
|
||||
if (userSetting.getDeviceStatusNotify()) {
|
||||
// 发送redis消息
|
||||
redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -423,17 +423,6 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
|
||||
|
||||
if (serverItem.isAutoConfig()) {
|
||||
// 查看assist服务的录像路径配置
|
||||
if (serverItem.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) {
|
||||
JSONObject info = assistRESTfulUtils.getInfo(serverItem, null);
|
||||
if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) {
|
||||
JSONObject dataJson = info.getJSONObject("data");
|
||||
if (dataJson != null) {
|
||||
String recordPath = dataJson.getString("record");
|
||||
userSetting.setRecordPath(recordPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
setZLMConfig(serverItem, "0".equals(zlmServerConfig.getHookEnable()));
|
||||
}
|
||||
final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + serverItem.getId();
|
||||
@ -568,7 +557,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
logger.info("[ZLM] 正在设置 :{} -> {}:{}",
|
||||
mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
|
||||
String protocol = sslEnabled ? "https" : "http";
|
||||
String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort);
|
||||
String hookPrefix = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort);
|
||||
|
||||
Map<String, Object> param = new HashMap<>();
|
||||
param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline
|
||||
@ -577,25 +566,21 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
}
|
||||
param.put("hook.enable","1");
|
||||
param.put("hook.on_flow_report","");
|
||||
param.put("hook.on_play",String.format("%s/on_play", hookPrex));
|
||||
param.put("hook.on_play",String.format("%s/on_play", hookPrefix));
|
||||
param.put("hook.on_http_access","");
|
||||
param.put("hook.on_publish", String.format("%s/on_publish", hookPrex));
|
||||
param.put("hook.on_publish", String.format("%s/on_publish", hookPrefix));
|
||||
param.put("hook.on_record_ts","");
|
||||
param.put("hook.on_rtsp_auth","");
|
||||
param.put("hook.on_rtsp_realm","");
|
||||
param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrex));
|
||||
param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrefix));
|
||||
param.put("hook.on_shell_login","");
|
||||
param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrex));
|
||||
param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex));
|
||||
param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex));
|
||||
param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrex));
|
||||
param.put("hook.on_send_rtp_stopped",String.format("%s/on_send_rtp_stopped", hookPrex));
|
||||
param.put("hook.on_rtp_server_timeout",String.format("%s/on_rtp_server_timeout", hookPrex));
|
||||
if (mediaServerItem.getRecordAssistPort() > 0) {
|
||||
param.put("hook.on_record_mp4",String.format("http://127.0.0.1:%s/api/record/on_record_mp4", mediaServerItem.getRecordAssistPort()));
|
||||
}else {
|
||||
param.put("hook.on_record_mp4","");
|
||||
}
|
||||
param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrefix));
|
||||
param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrefix));
|
||||
param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrefix));
|
||||
param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrefix));
|
||||
param.put("hook.on_send_rtp_stopped",String.format("%s/on_send_rtp_stopped", hookPrefix));
|
||||
param.put("hook.on_rtp_server_timeout",String.format("%s/on_rtp_server_timeout", hookPrefix));
|
||||
param.put("hook.on_record_mp4",String.format("%s/on_record_mp4", hookPrefix));
|
||||
param.put("hook.timeoutSec","20");
|
||||
// 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。
|
||||
// 置0关闭此特性(推流断开会导致立即断开播放器)
|
||||
@ -604,15 +589,14 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
param.put("protocol.continue_push_ms", "3000" );
|
||||
// 最多等待未初始化的Track时间,单位毫秒,超时之后会忽略未初始化的Track, 设置此选项优化那些音频错误的不规范流,
|
||||
// 等zlm支持给每个rtpServer设置关闭音频的时候可以不设置此选项
|
||||
// param.put("general.wait_track_ready_ms", "3000" );
|
||||
if (mediaServerItem.isRtpEnable() && !ObjectUtils.isEmpty(mediaServerItem.getRtpPortRange())) {
|
||||
param.put("rtp_proxy.port_range", mediaServerItem.getRtpPortRange().replace(",", "-"));
|
||||
}
|
||||
|
||||
if (userSetting.getRecordPath() != null) {
|
||||
File recordPathFile = new File(userSetting.getRecordPath());
|
||||
File mp4SavePathFile = recordPathFile.getParentFile().getAbsoluteFile();
|
||||
param.put("protocol.mp4_save_path", mp4SavePathFile.getAbsoluteFile());
|
||||
if (mediaServerItem.getRecordPath() != null) {
|
||||
File recordPathFile = new File(mediaServerItem.getRecordPath());
|
||||
param.put("protocol.mp4_save_path", recordPathFile.getParentFile().getPath());
|
||||
param.put("protocol.downloadRoot", recordPathFile.getParentFile().getPath());
|
||||
param.put("record.appName", recordPathFile.getName());
|
||||
}
|
||||
|
||||
@ -744,15 +728,6 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkRtpServer(MediaServerItem mediaServerItem, String app, String stream) {
|
||||
JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, stream);
|
||||
if(rtpInfo.getInteger("code") == 0){
|
||||
return rtpInfo.getBoolean("exist");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaServerLoad getLoad(MediaServerItem mediaServerItem) {
|
||||
MediaServerLoad result = new MediaServerLoad();
|
||||
@ -766,89 +741,8 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) {
|
||||
Assert.notNull(app, "app不存在");
|
||||
Assert.notNull(stream, "stream不存在");
|
||||
Assert.notNull(startTime, "startTime不存在");
|
||||
Assert.notNull(endTime, "endTime不存在");
|
||||
Assert.notEmpty(mediaServerItems, "流媒体列表为空");
|
||||
|
||||
CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()];
|
||||
for (int i = 0; i < mediaServerItems.size(); i++) {
|
||||
completableFutures[i] = getRecordFilesForOne(app, stream, startTime, endTime, mediaServerItems.get(i));
|
||||
}
|
||||
List<RecordFile> result = new ArrayList<>();
|
||||
for (int i = 0; i < completableFutures.length; i++) {
|
||||
try {
|
||||
List<RecordFile> list = (List<RecordFile>) completableFutures[i].get();
|
||||
if (!list.isEmpty()) {
|
||||
for (int g = 0; g < list.size(); g++) {
|
||||
list.get(g).setMediaServerId(mediaServerItems.get(i).getId());
|
||||
}
|
||||
result.addAll(list);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
Comparator<RecordFile> comparator = Comparator.comparing(RecordFile::getFileName);
|
||||
result.sort(comparator);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRecordDates(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems) {
|
||||
Assert.notNull(app, "app不存在");
|
||||
Assert.notNull(stream, "stream不存在");
|
||||
Assert.notEmpty(mediaServerItems, "流媒体列表为空");
|
||||
CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()];
|
||||
|
||||
for (int i = 0; i < mediaServerItems.size(); i++) {
|
||||
completableFutures[i] = getRecordDatesForOne(app, stream, year, month, mediaServerItems.get(i));
|
||||
}
|
||||
List<String> result = new ArrayList<>();
|
||||
CompletableFuture.allOf(completableFutures).join();
|
||||
for (CompletableFuture completableFuture : completableFutures) {
|
||||
try {
|
||||
List<String> list = (List<String>) completableFuture.get();
|
||||
result.addAll(list);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
Collections.sort(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Async
|
||||
public CompletableFuture<List<String>> getRecordDatesForOne(String app, String stream, int year, int month, MediaServerItem mediaServerItem) {
|
||||
JSONObject fileListJson = assistRESTfulUtils.getDateList(mediaServerItem, app, stream, year, month);
|
||||
if (fileListJson != null && !fileListJson.isEmpty()) {
|
||||
if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) {
|
||||
JSONArray data = fileListJson.getJSONArray("data");
|
||||
return CompletableFuture.completedFuture(data.toJavaList(String.class));
|
||||
}
|
||||
}
|
||||
return CompletableFuture.completedFuture(new ArrayList<>());
|
||||
}
|
||||
|
||||
@Async
|
||||
public CompletableFuture<List<RecordFile>> getRecordFilesForOne(String app, String stream, String startTime, String endTime, MediaServerItem mediaServerItem) {
|
||||
JSONObject fileListJson = assistRESTfulUtils.getFileList(mediaServerItem, 1, 100000000, app, stream, startTime, endTime);
|
||||
if (fileListJson != null && !fileListJson.isEmpty()) {
|
||||
if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) {
|
||||
JSONObject data = fileListJson.getJSONObject("data");
|
||||
JSONArray list = data.getJSONArray("list");
|
||||
if (list != null) {
|
||||
return CompletableFuture.completedFuture(list.toJavaList(RecordFile.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
return CompletableFuture.completedFuture(new ArrayList<>());
|
||||
public List<MediaServerItem> getAllWithAssistPort() {
|
||||
return mediaServerMapper.queryAllWithAssistPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -67,7 +67,7 @@ public class MediaServiceImpl implements IMediaService {
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class);
|
||||
JSONObject mediaJSON = data.getJSONObject(0);
|
||||
JSONArray tracks = mediaJSON.getJSONArray("tracks");
|
||||
if (authority) {
|
||||
streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr, calld);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.genersoft.iot.vmp.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.genersoft.iot.vmp.common.InviteInfo;
|
||||
import com.genersoft.iot.vmp.common.InviteSessionStatus;
|
||||
@ -13,26 +14,23 @@ import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
|
||||
import com.genersoft.iot.vmp.gb28181.bean.*;
|
||||
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
|
||||
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
|
||||
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.*;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
|
||||
import com.genersoft.iot.vmp.service.*;
|
||||
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
|
||||
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
|
||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||
import com.genersoft.iot.vmp.service.bean.*;
|
||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
|
||||
import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper;
|
||||
import com.genersoft.iot.vmp.utils.CloudRecordUtils;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import gov.nist.javax.sip.message.SIPResponse;
|
||||
@ -75,15 +73,15 @@ public class PlayServiceImpl implements IPlayService {
|
||||
@Autowired
|
||||
private IInviteStreamService inviteStreamService;
|
||||
|
||||
@Autowired
|
||||
private ZlmHttpHookSubscribe subscribe;
|
||||
|
||||
@Autowired
|
||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||
|
||||
@Autowired
|
||||
private ZLMServerFactory zlmServerFactory;
|
||||
|
||||
@Autowired
|
||||
private AssistRESTfulUtils assistRESTfulUtils;
|
||||
|
||||
@Autowired
|
||||
private IMediaService mediaService;
|
||||
|
||||
@ -103,7 +101,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
private DynamicTask dynamicTask;
|
||||
|
||||
@Autowired
|
||||
private ZlmHttpHookSubscribe subscribe;
|
||||
private CloudRecordServiceMapper cloudRecordServiceMapper;
|
||||
|
||||
|
||||
@Override
|
||||
@ -460,23 +458,6 @@ public class PlayServiceImpl implements IPlayService {
|
||||
return mediaServerItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MediaServerItem getNewMediaServerItemHasAssist(Device device) {
|
||||
if (device == null) {
|
||||
return null;
|
||||
}
|
||||
MediaServerItem mediaServerItem;
|
||||
if (ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) {
|
||||
mediaServerItem = mediaServerService.getMediaServerForMinimumLoad(true);
|
||||
} else {
|
||||
mediaServerItem = mediaServerService.getOne(device.getMediaServerId());
|
||||
}
|
||||
if (mediaServerItem == null) {
|
||||
logger.warn("[获取可用的ZLM节点]未找到可使用的ZLM...");
|
||||
}
|
||||
return mediaServerItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playBack(String deviceId, String channelId, String startTime,
|
||||
String endTime, ErrorCallback<Object> callback) {
|
||||
@ -686,7 +667,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||
if (device == null) {
|
||||
return;
|
||||
}
|
||||
MediaServerItem newMediaServerItem = getNewMediaServerItemHasAssist(device);
|
||||
MediaServerItem newMediaServerItem = this.getNewMediaServerItem(device);
|
||||
if (newMediaServerItem == null) {
|
||||
callback.run(InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getCode(),
|
||||
InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getMsg(),
|
||||
@ -765,6 +746,28 @@ public class PlayServiceImpl implements IPlayService {
|
||||
// 处理收到200ok后的TCP主动连接以及SSRC不一致的问题
|
||||
InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId,
|
||||
downLoadTimeOutTaskKey, callback, inviteInfo, InviteSessionType.DOWNLOAD);
|
||||
|
||||
// 注册录像回调事件,录像下载结束后写入下载地址
|
||||
ZlmHttpHookSubscribe.Event hookEventForRecord = (mediaServerItemInuse, hookParam) -> {
|
||||
logger.info("[录像下载] 收到录像写入磁盘消息: , {}/{}-{}",
|
||||
inviteInfo.getDeviceId(), inviteInfo.getChannelId(), ssrcInfo.getStream());
|
||||
logger.info("[录像下载] 收到录像写入磁盘消息内容: " + hookParam);
|
||||
OnRecordMp4HookParam recordMp4HookParam = (OnRecordMp4HookParam)hookParam;
|
||||
String filePath = recordMp4HookParam.getFile_path();
|
||||
DownloadFileInfo downloadFileInfo = CloudRecordUtils.getDownloadFilePath(mediaServerItem, filePath);
|
||||
InviteInfo inviteInfoForNew = inviteStreamService.getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId()
|
||||
, inviteInfo.getChannelId(), inviteInfo.getStream());
|
||||
inviteInfoForNew.getStreamInfo().setDownLoadFilePath(downloadFileInfo);
|
||||
inviteStreamService.updateInviteInfo(inviteInfoForNew);
|
||||
};
|
||||
HookSubscribeForRecordMp4 hookSubscribe = HookSubscribeFactory.on_record_mp4(
|
||||
mediaServerItem.getId(), "rtp", ssrcInfo.getStream());
|
||||
|
||||
// 设置过期时间,下载失败时自动处理订阅数据
|
||||
// long difference = DateUtil.getDifference(startTime, endTime)/1000;
|
||||
// Instant expiresInstant = Instant.now().plusSeconds(TimeUnit.MINUTES.toSeconds(difference * 2));
|
||||
// hookSubscribe.setExpires(expiresInstant);
|
||||
subscribe.addSubscribe(hookSubscribe, hookEventForRecord);
|
||||
});
|
||||
} catch (InvalidArgumentException | SipException | ParseException e) {
|
||||
logger.error("[命令发送失败] 录像下载: {}", e.getMessage());
|
||||
@ -780,47 +783,71 @@ public class PlayServiceImpl implements IPlayService {
|
||||
@Override
|
||||
public StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream) {
|
||||
InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, stream);
|
||||
if (inviteInfo == null || inviteInfo.getStreamInfo() == null) {
|
||||
logger.warn("[获取下载进度] 未查询到录像下载的信息");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (inviteInfo != null && inviteInfo.getStreamInfo() != null) {
|
||||
if (inviteInfo.getStreamInfo().getProgress() == 1) {
|
||||
return inviteInfo.getStreamInfo();
|
||||
}
|
||||
|
||||
// 获取当前已下载时长
|
||||
String mediaServerId = inviteInfo.getStreamInfo().getMediaServerId();
|
||||
MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaServerItem == null) {
|
||||
logger.warn("查询录像信息时发现节点已离线");
|
||||
return null;
|
||||
}
|
||||
if (mediaServerItem.getRecordAssistPort() > 0) {
|
||||
JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, inviteInfo.getStreamInfo().getApp(), inviteInfo.getStreamInfo().getStream(), null);
|
||||
if (jsonObject == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接Assist服务失败");
|
||||
}
|
||||
if (jsonObject.getInteger("code") == 0) {
|
||||
long duration = jsonObject.getLong("data");
|
||||
|
||||
if (duration == 0) {
|
||||
inviteInfo.getStreamInfo().setProgress(0);
|
||||
} else {
|
||||
String startTime = inviteInfo.getStreamInfo().getStartTime();
|
||||
String endTime = inviteInfo.getStreamInfo().getEndTime();
|
||||
long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime);
|
||||
long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
|
||||
|
||||
BigDecimal currentCount = new BigDecimal(duration / 1000);
|
||||
BigDecimal totalCount = new BigDecimal(end - start);
|
||||
BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP);
|
||||
double process = divide.doubleValue();
|
||||
inviteInfo.getStreamInfo().setProgress(process);
|
||||
}
|
||||
inviteStreamService.updateInviteInfo(inviteInfo);
|
||||
}
|
||||
}
|
||||
if (inviteInfo.getStreamInfo().getProgress() == 1) {
|
||||
return inviteInfo.getStreamInfo();
|
||||
}
|
||||
return null;
|
||||
|
||||
// 获取当前已下载时长
|
||||
String mediaServerId = inviteInfo.getStreamInfo().getMediaServerId();
|
||||
MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||
if (mediaServerItem == null) {
|
||||
logger.warn("[获取下载进度] 查询录像信息时发现节点不存在");
|
||||
return null;
|
||||
}
|
||||
SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, null, stream);
|
||||
|
||||
if (ssrcTransaction == null) {
|
||||
logger.warn("[获取下载进度] 下载已结束");
|
||||
return null;
|
||||
}
|
||||
|
||||
JSONObject mediaListJson= zlmresTfulUtils.getMediaList(mediaServerItem, "rtp", stream);
|
||||
if (mediaListJson == null) {
|
||||
logger.warn("[获取下载进度] 从zlm查询进度失败");
|
||||
return null;
|
||||
}
|
||||
if (mediaListJson.getInteger("code") != 0) {
|
||||
logger.warn("[获取下载进度] 从zlm查询进度出现错误: {}", mediaListJson.getString("msg"));
|
||||
return null;
|
||||
}
|
||||
JSONArray data = mediaListJson.getJSONArray("data");
|
||||
if (data == null) {
|
||||
logger.warn("[获取下载进度] 从zlm查询进度时未返回数据");
|
||||
return null;
|
||||
}
|
||||
JSONObject mediaJSON = data.getJSONObject(0);
|
||||
JSONArray tracks = mediaJSON.getJSONArray("tracks");
|
||||
if (tracks.isEmpty()) {
|
||||
logger.warn("[获取下载进度] 从zlm查询进度时未返回数据");
|
||||
return null;
|
||||
}
|
||||
JSONObject jsonObject = tracks.getJSONObject(0);
|
||||
long duration = jsonObject.getLongValue("duration");
|
||||
if (duration == 0) {
|
||||
inviteInfo.getStreamInfo().setProgress(0);
|
||||
} else {
|
||||
String startTime = inviteInfo.getStreamInfo().getStartTime();
|
||||
String endTime = inviteInfo.getStreamInfo().getEndTime();
|
||||
// 此时start和end单位是秒
|
||||
long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime);
|
||||
long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime);
|
||||
|
||||
BigDecimal currentCount = new BigDecimal(duration);
|
||||
BigDecimal totalCount = new BigDecimal((end - start) * 1000);
|
||||
BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP);
|
||||
double process = divide.doubleValue();
|
||||
if (process > 0.999) {
|
||||
process = 1.0;
|
||||
}
|
||||
inviteInfo.getStreamInfo().setProgress(process);
|
||||
}
|
||||
inviteStreamService.updateInviteInfo(inviteInfo);
|
||||
return inviteInfo.getStreamInfo();
|
||||
}
|
||||
|
||||
private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, HookParam hookParam, String deviceId, String channelId, String startTime, String endTime) {
|
||||
|
||||
@ -123,7 +123,13 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
}
|
||||
JSONArray dataArray = jsonObject.getJSONArray("data");
|
||||
JSONObject mediaServerConfig = dataArray.getJSONObject(0);
|
||||
if (ObjectUtils.isEmpty(param.getFfmpegCmdKey())) {
|
||||
param.setFfmpegCmdKey("ffmpeg.cmd");
|
||||
}
|
||||
String ffmpegCmd = mediaServerConfig.getString(param.getFfmpegCmdKey());
|
||||
if (ffmpegCmd == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "ffmpeg拉流代理无法获取ffmpeg cmd");
|
||||
}
|
||||
String schema = getSchemaFromFFmpegCmd(ffmpegCmd);
|
||||
if (schema == null) {
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "ffmpeg拉流代理无法从ffmpeg cmd中获取到输出格式");
|
||||
@ -412,7 +418,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||
streamProxyMapper.deleteAutoRemoveItemByMediaServerId(mediaServerId);
|
||||
|
||||
// 移除拉流代理生成的流信息
|
||||
// syncPullStream(mediaServerId);
|
||||
syncPullStream(mediaServerId);
|
||||
|
||||
// 恢复流代理, 只查找这个这个流媒体
|
||||
List<StreamProxy> streamProxyListForEnable = storager.getStreamProxyListForEnableInMediaServer(
|
||||
|
||||
@ -226,6 +226,8 @@ public class StreamPushServiceImpl implements IStreamPushService {
|
||||
redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
|
||||
// 移除redis内流的信息
|
||||
redisCatchStorage.removeStream(mediaServerItem.getId(), "PUSH", offlineOnStreamChangedHookParam.getApp(), offlineOnStreamChangedHookParam.getStream());
|
||||
// 冗余数据,自己系统中自用
|
||||
redisCatchStorage.removePushListItem(offlineOnStreamChangedHookParam.getApp(), offlineOnStreamChangedHookParam.getStream(), mediaServerItem.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,6 +264,9 @@ public class StreamPushServiceImpl implements IStreamPushService {
|
||||
jsonObject.put("register", false);
|
||||
jsonObject.put("mediaServerId", mediaServerId);
|
||||
redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
|
||||
|
||||
// 冗余数据,自己系统中自用
|
||||
redisCatchStorage.removePushListItem(onStreamChangedHookParam.getApp(), onStreamChangedHookParam.getStream(), mediaServerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,4 +208,8 @@ public interface IRedisCatchStorage {
|
||||
void sendPlatformStartPlayMsg(MessageForPushChannel messageForPushChannel);
|
||||
|
||||
void sendPlatformStopPlayMsg(MessageForPushChannel messageForPushChannel);
|
||||
|
||||
void addPushListItem(String app, String stream, OnStreamChangedHookParam param);
|
||||
|
||||
void removePushListItem(String app, String stream, String mediaServerId);
|
||||
}
|
||||
|
||||
@ -0,0 +1,122 @@
|
||||
package com.genersoft.iot.vmp.storager.dao;
|
||||
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface CloudRecordServiceMapper {
|
||||
|
||||
@Insert(" <script>" +
|
||||
"INSERT INTO wvp_cloud_record (" +
|
||||
" app," +
|
||||
" stream," +
|
||||
"<if test=\"callId != null\"> call_id,</if>" +
|
||||
" start_time," +
|
||||
" end_time," +
|
||||
" media_server_id," +
|
||||
" file_name," +
|
||||
" folder," +
|
||||
" file_path," +
|
||||
" file_size," +
|
||||
" time_len ) " +
|
||||
"VALUES (" +
|
||||
" #{app}," +
|
||||
" #{stream}," +
|
||||
" <if test=\"callId != null\"> #{callId},</if>" +
|
||||
" #{startTime}," +
|
||||
" #{endTime}," +
|
||||
" #{mediaServerId}," +
|
||||
" #{fileName}," +
|
||||
" #{folder}," +
|
||||
" #{filePath}," +
|
||||
" #{fileSize}," +
|
||||
" #{timeLen})" +
|
||||
" </script>")
|
||||
int add(CloudRecordItem cloudRecordItem);
|
||||
|
||||
@Select(" <script>" +
|
||||
"select * " +
|
||||
" from wvp_cloud_record " +
|
||||
" where 0 = 0" +
|
||||
" <if test='query != null'> AND (app LIKE concat('%',#{query},'%') OR stream LIKE concat('%',#{query},'%') )</if> " +
|
||||
" <if test= 'app != null '> and app=#{app}</if>" +
|
||||
" <if test= 'stream != null '> and stream=#{stream}</if>" +
|
||||
" <if test= 'startTimeStamp != null '> and end_time >= #{startTimeStamp}</if>" +
|
||||
" <if test= 'endTimeStamp != null '> and start_time <= #{endTimeStamp}</if>" +
|
||||
" <if test= 'callId != null '> and call_id = #{callId}</if>" +
|
||||
" <if test= 'mediaServerItemList != null ' > and media_server_id in " +
|
||||
" <foreach collection='mediaServerItemList' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" +
|
||||
" </if>" +
|
||||
" order by start_time DESC" +
|
||||
|
||||
" </script>")
|
||||
List<CloudRecordItem> getList(@Param("query") String query, @Param("app") String app, @Param("stream") String stream,
|
||||
@Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp,
|
||||
@Param("callId")String callId, List<MediaServerItem> mediaServerItemList);
|
||||
|
||||
|
||||
@Select(" <script>" +
|
||||
"select file_path" +
|
||||
" from wvp_cloud_record " +
|
||||
" where 0 = 0" +
|
||||
" <if test= 'app != null '> and app=#{app}</if>" +
|
||||
" <if test= 'stream != null '> and stream=#{stream}</if>" +
|
||||
" <if test= 'startTimeStamp != null '> and end_time >= #{startTimeStamp}</if>" +
|
||||
" <if test= 'endTimeStamp != null '> and start_time <= #{endTimeStamp}</if>" +
|
||||
" <if test= 'callId != null '> and call_id = #{callId}</if>" +
|
||||
" <if test= 'mediaServerItemList != null ' > and media_server_id in " +
|
||||
" <foreach collection='mediaServerItemList' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" +
|
||||
" </if>" +
|
||||
" </script>")
|
||||
List<String> queryRecordFilePathList(@Param("app") String app, @Param("stream") String stream,
|
||||
@Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp,
|
||||
@Param("callId")String callId, List<MediaServerItem> mediaServerItemList);
|
||||
|
||||
@Update(" <script>" +
|
||||
"update wvp_cloud_record set collect = #{collect} where file_path in " +
|
||||
" <foreach collection='cloudRecordItemList' item='item' open='(' separator=',' close=')' > #{item.filePath}</foreach>" +
|
||||
" </script>")
|
||||
int updateCollectList(@Param("collect") boolean collect, List<CloudRecordItem> cloudRecordItemList);
|
||||
|
||||
@Delete(" <script>" +
|
||||
"delete from wvp_cloud_record where media_server_id=#{mediaServerId} and file_path in " +
|
||||
" <foreach collection='filePathList' item='item' open='(' separator=',' close=')' > #{item}</foreach>" +
|
||||
" </script>")
|
||||
void deleteByFileList(List<String> filePathList, @Param("mediaServerId") String mediaServerId);
|
||||
|
||||
|
||||
@Select(" <script>" +
|
||||
"select *" +
|
||||
" from wvp_cloud_record " +
|
||||
" where collect = false and end_time <= #{endTimeStamp} and media_server_id = #{mediaServerId} " +
|
||||
" </script>")
|
||||
List<CloudRecordItem> queryRecordListForDelete(@Param("endTimeStamp")Long endTimeStamp, String mediaServerId);
|
||||
|
||||
@Update(" <script>" +
|
||||
"update wvp_cloud_record set collect = #{collect} where id = #{recordId} " +
|
||||
" </script>")
|
||||
int changeCollectById(@Param("collect") boolean collect, @Param("recordId") Integer recordId);
|
||||
|
||||
@Delete(" <script>" +
|
||||
"delete from wvp_cloud_record where id in " +
|
||||
" <foreach collection='cloudRecordItemIdList' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" +
|
||||
" </script>")
|
||||
int deleteList(List<CloudRecordItem> cloudRecordItemIdList);
|
||||
|
||||
@Select(" <script>" +
|
||||
"select *" +
|
||||
" from wvp_cloud_record " +
|
||||
"where call_id = #{callId}" +
|
||||
" </script>")
|
||||
List<CloudRecordItem> getListByCallId(@Param("callId") String callId);
|
||||
|
||||
@Select(" <script>" +
|
||||
"select *" +
|
||||
" from wvp_cloud_record " +
|
||||
"where id = #{id}" +
|
||||
" </script>")
|
||||
CloudRecordItem queryOne(@Param("id") Integer id);
|
||||
}
|
||||
@ -31,6 +31,8 @@ public interface MediaServerMapper {
|
||||
"rtp_port_range,"+
|
||||
"send_rtp_port_range,"+
|
||||
"record_assist_port,"+
|
||||
"record_day,"+
|
||||
"record_path,"+
|
||||
"default_server,"+
|
||||
"create_time,"+
|
||||
"update_time,"+
|
||||
@ -55,6 +57,8 @@ public interface MediaServerMapper {
|
||||
"#{rtpPortRange}, " +
|
||||
"#{sendRtpPortRange}, " +
|
||||
"#{recordAssistPort}, " +
|
||||
"#{recordDay}, " +
|
||||
"#{recordPath}, " +
|
||||
"#{defaultServer}, " +
|
||||
"#{createTime}, " +
|
||||
"#{updateTime}, " +
|
||||
@ -82,6 +86,8 @@ public interface MediaServerMapper {
|
||||
"<if test=\"secret != null\">, secret=#{secret}</if>" +
|
||||
"<if test=\"recordAssistPort != null\">, record_assist_port=#{recordAssistPort}</if>" +
|
||||
"<if test=\"hookAliveInterval != null\">, hook_alive_interval=#{hookAliveInterval}</if>" +
|
||||
"<if test=\"recordDay != null\">, record_day=#{recordDay}</if>" +
|
||||
"<if test=\"recordPath != null\">, record_path=#{recordPath}</if>" +
|
||||
"WHERE id=#{id}"+
|
||||
" </script>"})
|
||||
int update(MediaServerItem mediaServerItem);
|
||||
@ -105,6 +111,8 @@ public interface MediaServerMapper {
|
||||
"<if test=\"sendRtpPortRange != null\">, send_rtp_port_range=#{sendRtpPortRange}</if>" +
|
||||
"<if test=\"secret != null\">, secret=#{secret}</if>" +
|
||||
"<if test=\"recordAssistPort != null\">, record_assist_port=#{recordAssistPort}</if>" +
|
||||
"<if test=\"recordDay != null\">, record_day=#{recordDay}</if>" +
|
||||
"<if test=\"recordPath != null\">, record_path=#{recordPath}</if>" +
|
||||
"<if test=\"hookAliveInterval != null\">, hook_alive_interval=#{hookAliveInterval}</if>" +
|
||||
"WHERE ip=#{ip} and http_port=#{httpPort}"+
|
||||
" </script>"})
|
||||
@ -130,4 +138,8 @@ public interface MediaServerMapper {
|
||||
|
||||
@Select("SELECT * FROM wvp_media_server WHERE default_server=true")
|
||||
MediaServerItem queryDefault();
|
||||
|
||||
@Select("SELECT * FROM wvp_media_server WHERE record_assist_port > 0")
|
||||
List<MediaServerItem> queryAllWithAssistPort();
|
||||
|
||||
}
|
||||
|
||||
@ -609,14 +609,13 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
|
||||
@Override
|
||||
public void sendDeviceOrChannelStatus(String deviceId, String channelId, boolean online) {
|
||||
String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_DEVICE_STATUS;
|
||||
logger.info("[redis通知] 发送 推送设备/通道状态, {}/{}-{}", deviceId, channelId, online);
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append(deviceId);
|
||||
if (channelId != null) {
|
||||
msg.append(":").append(channelId);
|
||||
}
|
||||
msg.append(" ").append(online? "ON":"OFF");
|
||||
logger.info("[redis通知] 推送状态-> {} ", msg);
|
||||
logger.info("[redis通知] 推送设备/通道状态-> {} ", msg);
|
||||
// 使用 RedisTemplate<Object, Object> 发送字符串消息会导致发送的消息多带了双引号
|
||||
stringRedisTemplate.convertAndSend(key, msg.toString());
|
||||
}
|
||||
@ -650,4 +649,20 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
|
||||
logger.info("[redis发送通知] 发送 上级平台停止观看 {}: {}/{}->{}", key, msg.getApp(), msg.getStream(), msg.getPlatFormId());
|
||||
redisTemplate.convertAndSend(key, JSON.toJSON(msg));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPushListItem(String app, String stream, OnStreamChangedHookParam param) {
|
||||
String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream;
|
||||
redisTemplate.opsForValue().set(key, param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePushListItem(String app, String stream, String mediaServerId) {
|
||||
String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream;
|
||||
OnStreamChangedHookParam param = (OnStreamChangedHookParam)redisTemplate.opsForValue().get(key);
|
||||
if (param != null && param.getMediaServerId().equalsIgnoreCase(mediaServerId)) {
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
package com.genersoft.iot.vmp.utils;
|
||||
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
|
||||
|
||||
public class CloudRecordUtils {
|
||||
|
||||
public static DownloadFileInfo getDownloadFilePath(MediaServerItem mediaServerItem, String filePath) {
|
||||
DownloadFileInfo downloadFileInfo = new DownloadFileInfo();
|
||||
|
||||
String pathTemplate = "%s://%s:%s/index/api/downloadFile?file_path=" + filePath;
|
||||
|
||||
downloadFileInfo.setHttpPath(String.format(pathTemplate, "http", mediaServerItem.getStreamIp(),
|
||||
mediaServerItem.getHttpPort()));
|
||||
|
||||
if (mediaServerItem.getHttpSSlPort() > 0) {
|
||||
downloadFileInfo.setHttpsPath(String.format(pathTemplate, "https", mediaServerItem.getStreamIp(),
|
||||
mediaServerItem.getHttpSSlPort()));
|
||||
}
|
||||
return downloadFileInfo;
|
||||
}
|
||||
}
|
||||
@ -40,11 +40,17 @@ public class DateUtil {
|
||||
*/
|
||||
public static final String URL_PATTERN = "yyyyMMddHHmmss";
|
||||
|
||||
/**
|
||||
* 日期格式
|
||||
*/
|
||||
public static final String date_PATTERN = "yyyy-MM-dd";
|
||||
|
||||
public static final String zoneStr = "Asia/Shanghai";
|
||||
|
||||
public static final DateTimeFormatter formatterCompatibleISO8601 = DateTimeFormatter.ofPattern(ISO8601_COMPATIBLE_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
|
||||
public static final DateTimeFormatter formatterISO8601 = DateTimeFormatter.ofPattern(ISO8601_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
|
||||
public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
|
||||
public static final DateTimeFormatter DateFormatter = DateTimeFormatter.ofPattern(date_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
|
||||
public static final DateTimeFormatter urlFormatter = DateTimeFormatter.ofPattern(URL_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr));
|
||||
|
||||
public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) {
|
||||
@ -71,6 +77,22 @@ public class DateUtil {
|
||||
return instant.getEpochSecond();
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间戳 转 yyyy_MM_dd_HH_mm_ss
|
||||
*/
|
||||
public static String timestampTo_yyyy_MM_dd_HH_mm_ss(long timestamp) {
|
||||
Instant instant = Instant.ofEpochSecond(timestamp);
|
||||
return formatter.format(LocalDateTime.ofInstant(instant, ZoneId.of(zoneStr)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间戳 转 yyyy_MM_dd
|
||||
*/
|
||||
public static String timestampTo_yyyy_MM_dd(long timestamp) {
|
||||
Instant instant = Instant.ofEpochMilli(timestamp);
|
||||
return DateFormatter.format(LocalDateTime.ofInstant(instant, ZoneId.of(zoneStr)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间
|
||||
* @return
|
||||
@ -117,4 +139,13 @@ public class DateUtil {
|
||||
Instant beforeInstant = Instant.from(formatter.parse(keepaliveTime));
|
||||
return ChronoUnit.MILLIS.between(beforeInstant, Instant.now());
|
||||
}
|
||||
|
||||
public static long getDifference(String startTime, String endTime) {
|
||||
if (ObjectUtils.isEmpty(startTime) || ObjectUtils.isEmpty(endTime)) {
|
||||
return 0;
|
||||
}
|
||||
Instant startInstant = Instant.from(formatter.parse(startTime));
|
||||
Instant endInstant = Instant.from(formatter.parse(endTime));
|
||||
return ChronoUnit.MILLIS.between(endInstant, startInstant);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.genersoft.iot.vmp.vmanager.bean;
|
||||
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
@Schema(description = "流信息")
|
||||
@ -93,6 +94,9 @@ public class StreamContent {
|
||||
@Schema(description = "结束时间")
|
||||
private String endTime;
|
||||
|
||||
@Schema(description = "文件下载地址(录像下载使用)")
|
||||
private DownloadFileInfo downLoadFilePath;
|
||||
|
||||
private double progress;
|
||||
|
||||
public StreamContent(StreamInfo streamInfo) {
|
||||
@ -170,6 +174,10 @@ public class StreamContent {
|
||||
this.startTime = streamInfo.getStartTime();
|
||||
this.endTime = streamInfo.getEndTime();
|
||||
this.progress = streamInfo.getProgress();
|
||||
|
||||
if (streamInfo.getDownLoadFilePath() != null) {
|
||||
this.downLoadFilePath = streamInfo.getDownLoadFilePath();
|
||||
}
|
||||
}
|
||||
|
||||
public String getApp() {
|
||||
@ -411,4 +419,12 @@ public class StreamContent {
|
||||
public void setProgress(double progress) {
|
||||
this.progress = progress;
|
||||
}
|
||||
|
||||
public DownloadFileInfo getDownLoadFilePath() {
|
||||
return downLoadFilePath;
|
||||
}
|
||||
|
||||
public void setDownLoadFilePath(DownloadFileInfo downLoadFilePath) {
|
||||
this.downLoadFilePath = downLoadFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,17 +1,21 @@
|
||||
package com.genersoft.iot.vmp.vmanager.cloudRecord;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.genersoft.iot.vmp.conf.DynamicTask;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
import com.genersoft.iot.vmp.conf.security.JwtUtils;
|
||||
import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
|
||||
import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
|
||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||
import com.genersoft.iot.vmp.service.ICloudRecordService;
|
||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
|
||||
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.WVPPageInfo;
|
||||
import com.genersoft.iot.vmp.vmanager.bean.RecordFile;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
@ -34,28 +38,15 @@ import java.util.List;
|
||||
@RequestMapping("/api/cloud/record")
|
||||
public class CloudRecordController {
|
||||
|
||||
@Autowired
|
||||
private ZLMServerFactory zlmServerFactory;
|
||||
|
||||
@Autowired
|
||||
private SendRtpPortManager sendRtpPortManager;
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(CloudRecordController.class);
|
||||
|
||||
@Autowired
|
||||
private ZlmHttpHookSubscribe hookSubscribe;
|
||||
private ICloudRecordService cloudRecordService;
|
||||
|
||||
@Autowired
|
||||
private IMediaServerService mediaServerService;
|
||||
|
||||
@Autowired
|
||||
private UserSetting userSetting;
|
||||
|
||||
@Autowired
|
||||
private DynamicTask dynamicTask;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<Object, Object> redisTemplate;
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/date/list")
|
||||
@ -66,8 +57,8 @@ public class CloudRecordController {
|
||||
@Parameter(name = "month", description = "月,置空则查询当月", required = false)
|
||||
@Parameter(name = "mediaServerId", description = "流媒体ID,置空则查询全部", required = false)
|
||||
public List<String> openRtpServer(
|
||||
@RequestParam String app,
|
||||
@RequestParam String stream,
|
||||
@RequestParam(required = true) String app,
|
||||
@RequestParam(required = true) String stream,
|
||||
@RequestParam(required = false) int year,
|
||||
@RequestParam(required = false) int month,
|
||||
@RequestParam(required = false) String mediaServerId
|
||||
@ -97,26 +88,28 @@ public class CloudRecordController {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
return mediaServerService.getRecordDates(app, stream, year, month, mediaServerItems);
|
||||
return cloudRecordService.getDateList(app, stream, year, month, mediaServerItems);
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "分页查询云端录像", security = @SecurityRequirement(name = JwtUtils.HEADER))
|
||||
@Parameter(name = "app", description = "应用名", required = true)
|
||||
@Parameter(name = "stream", description = "流ID", required = true)
|
||||
@Parameter(name = "page", description = "当前页", required = false)
|
||||
@Parameter(name = "count", description = "每页查询数量", required = false)
|
||||
@Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = true)
|
||||
@Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = true)
|
||||
@Parameter(name = "query", description = "检索内容", required = false)
|
||||
@Parameter(name = "app", description = "应用名", required = false)
|
||||
@Parameter(name = "stream", description = "流ID", required = false)
|
||||
@Parameter(name = "page", description = "当前页", required = true)
|
||||
@Parameter(name = "count", description = "每页查询数量", required = true)
|
||||
@Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = false)
|
||||
@Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = false)
|
||||
@Parameter(name = "mediaServerId", description = "流媒体ID,置空则查询全部流媒体", required = false)
|
||||
public WVPPageInfo<RecordFile> openRtpServer(
|
||||
@RequestParam String app,
|
||||
@RequestParam String stream,
|
||||
public PageInfo<CloudRecordItem> openRtpServer(
|
||||
@RequestParam(required = false) String query,
|
||||
@RequestParam(required = false) String app,
|
||||
@RequestParam(required = false) String stream,
|
||||
@RequestParam int page,
|
||||
@RequestParam int count,
|
||||
@RequestParam String startTime,
|
||||
@RequestParam String endTime,
|
||||
@RequestParam(required = false) String startTime,
|
||||
@RequestParam(required = false) String endTime,
|
||||
@RequestParam(required = false) String mediaServerId
|
||||
|
||||
) {
|
||||
@ -135,13 +128,128 @@ public class CloudRecordController {
|
||||
mediaServerItems = mediaServerService.getAll();
|
||||
}
|
||||
if (mediaServerItems.isEmpty()) {
|
||||
return new WVPPageInfo<>();
|
||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "当前无流媒体");
|
||||
}
|
||||
List<RecordFile> records = mediaServerService.getRecords(app, stream, startTime, endTime, mediaServerItems);
|
||||
WVPPageInfo<RecordFile> pageInfo = new WVPPageInfo<>(records);
|
||||
pageInfo.startPage(page, count);
|
||||
return pageInfo;
|
||||
if (query != null && ObjectUtils.isEmpty(query.trim())) {
|
||||
query = null;
|
||||
}
|
||||
if (app != null && ObjectUtils.isEmpty(app.trim())) {
|
||||
app = null;
|
||||
}
|
||||
if (stream != null && ObjectUtils.isEmpty(stream.trim())) {
|
||||
stream = null;
|
||||
}
|
||||
if (startTime != null && ObjectUtils.isEmpty(startTime.trim())) {
|
||||
startTime = null;
|
||||
}
|
||||
if (endTime != null && ObjectUtils.isEmpty(endTime.trim())) {
|
||||
endTime = null;
|
||||
}
|
||||
return cloudRecordService.getList(page, count, query, app, stream, startTime, endTime, mediaServerItems);
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/task/add")
|
||||
@Operation(summary = "添加合并任务")
|
||||
@Parameter(name = "app", description = "应用名", required = false)
|
||||
@Parameter(name = "stream", description = "流ID", required = false)
|
||||
@Parameter(name = "mediaServerId", description = "流媒体ID", required = false)
|
||||
@Parameter(name = "startTime", description = "鉴权ID", required = false)
|
||||
@Parameter(name = "endTime", description = "鉴权ID", required = false)
|
||||
@Parameter(name = "callId", description = "鉴权ID", required = false)
|
||||
@Parameter(name = "remoteHost", description = "返回地址时的远程地址", required = false)
|
||||
public String addTask(
|
||||
@RequestParam(required = false) String app,
|
||||
@RequestParam(required = false) String stream,
|
||||
@RequestParam(required = false) String mediaServerId,
|
||||
@RequestParam(required = false) String startTime,
|
||||
@RequestParam(required = false) String endTime,
|
||||
@RequestParam(required = false) String callId,
|
||||
@RequestParam(required = false) String remoteHost
|
||||
){
|
||||
return cloudRecordService.addTask(app, stream, mediaServerId, startTime, endTime, callId, remoteHost);
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/task/list")
|
||||
@Operation(summary = "查询合并任务")
|
||||
@Parameter(name = "taskId", description = "任务Id", required = false)
|
||||
@Parameter(name = "mediaServerId", description = "流媒体ID", required = false)
|
||||
@Parameter(name = "isEnd", description = "是否结束", required = false)
|
||||
public JSONArray queryTaskList(
|
||||
@RequestParam(required = false) String app,
|
||||
@RequestParam(required = false) String stream,
|
||||
@RequestParam(required = false) String callId,
|
||||
@RequestParam(required = false) String taskId,
|
||||
@RequestParam(required = false) String mediaServerId,
|
||||
@RequestParam(required = false) Boolean isEnd
|
||||
){
|
||||
return cloudRecordService.queryTask(app, stream, callId, taskId, mediaServerId, isEnd);
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/collect/add")
|
||||
@Operation(summary = "添加收藏")
|
||||
@Parameter(name = "app", description = "应用名", required = false)
|
||||
@Parameter(name = "stream", description = "流ID", required = false)
|
||||
@Parameter(name = "mediaServerId", description = "流媒体ID", required = false)
|
||||
@Parameter(name = "startTime", description = "鉴权ID", required = false)
|
||||
@Parameter(name = "endTime", description = "鉴权ID", required = false)
|
||||
@Parameter(name = "callId", description = "鉴权ID", required = false)
|
||||
@Parameter(name = "recordId", description = "录像记录的ID,用于精准收藏一个视频文件", required = false)
|
||||
public int addCollect(
|
||||
@RequestParam(required = false) String app,
|
||||
@RequestParam(required = false) String stream,
|
||||
@RequestParam(required = false) String mediaServerId,
|
||||
@RequestParam(required = false) String startTime,
|
||||
@RequestParam(required = false) String endTime,
|
||||
@RequestParam(required = false) String callId,
|
||||
@RequestParam(required = false) Integer recordId
|
||||
){
|
||||
logger.info("[云端录像] 添加收藏,app={},stream={},mediaServerId={},startTime={},endTime={},callId={},recordId={}",
|
||||
app, stream, mediaServerId, startTime, endTime, callId, recordId);
|
||||
if (recordId != null) {
|
||||
return cloudRecordService.changeCollectById(recordId, true);
|
||||
}else {
|
||||
return cloudRecordService.changeCollect(true, app, stream, mediaServerId, startTime, endTime, callId);
|
||||
}
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/collect/delete")
|
||||
@Operation(summary = "移除收藏")
|
||||
@Parameter(name = "app", description = "应用名", required = false)
|
||||
@Parameter(name = "stream", description = "流ID", required = false)
|
||||
@Parameter(name = "mediaServerId", description = "流媒体ID", required = false)
|
||||
@Parameter(name = "startTime", description = "鉴权ID", required = false)
|
||||
@Parameter(name = "endTime", description = "鉴权ID", required = false)
|
||||
@Parameter(name = "callId", description = "鉴权ID", required = false)
|
||||
@Parameter(name = "recordId", description = "录像记录的ID,用于精准精准移除一个视频文件的收藏", required = false)
|
||||
public int deleteCollect(
|
||||
@RequestParam(required = false) String app,
|
||||
@RequestParam(required = false) String stream,
|
||||
@RequestParam(required = false) String mediaServerId,
|
||||
@RequestParam(required = false) String startTime,
|
||||
@RequestParam(required = false) String endTime,
|
||||
@RequestParam(required = false) String callId,
|
||||
@RequestParam(required = false) Integer recordId
|
||||
){
|
||||
logger.info("[云端录像] 移除收藏,app={},stream={},mediaServerId={},startTime={},endTime={},callId={},recordId={}",
|
||||
app, stream, mediaServerId, startTime, endTime, callId, recordId);
|
||||
if (recordId != null) {
|
||||
return cloudRecordService.changeCollectById(recordId, false);
|
||||
}else {
|
||||
return cloudRecordService.changeCollect(false, app, stream, mediaServerId, startTime, endTime, callId);
|
||||
}
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/play/path")
|
||||
@Operation(summary = "获取播放地址")
|
||||
@Parameter(name = "recordId", description = "录像记录的ID", required = true)
|
||||
public DownloadFileInfo getPlayUrlPath(
|
||||
@RequestParam(required = true) Integer recordId
|
||||
){
|
||||
return cloudRecordService.getPlayUrlPath(recordId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package com.genersoft.iot.vmp.vmanager.gb28181.record;
|
||||
|
||||
import com.genersoft.iot.vmp.common.InviteInfo;
|
||||
import com.genersoft.iot.vmp.common.InviteSessionType;
|
||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||
import com.genersoft.iot.vmp.conf.UserSetting;
|
||||
import com.genersoft.iot.vmp.conf.exception.ControllerException;
|
||||
@ -11,7 +13,9 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
|
||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
||||
import com.genersoft.iot.vmp.service.IDeviceService;
|
||||
import com.genersoft.iot.vmp.service.IInviteStreamService;
|
||||
import com.genersoft.iot.vmp.service.IPlayService;
|
||||
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
|
||||
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
|
||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
|
||||
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||
@ -25,6 +29,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -57,6 +62,9 @@ public class GBRecordController {
|
||||
@Autowired
|
||||
private IPlayService playService;
|
||||
|
||||
@Autowired
|
||||
private IInviteStreamService inviteStreamService;
|
||||
|
||||
@Autowired
|
||||
private IDeviceService deviceService;
|
||||
|
||||
|
||||
@ -1,51 +0,0 @@
|
||||
//package com.genersoft.iot.vmp.vmanager.record;
|
||||
//
|
||||
//import com.alibaba.fastjson2.JSONObject;
|
||||
//import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
|
||||
//import com.genersoft.iot.vmp.service.IRecordInfoServer;
|
||||
//import com.genersoft.iot.vmp.storager.dao.dto.RecordInfo;
|
||||
//import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||
//import com.github.pagehelper.PageInfo;
|
||||
//import io.swagger.annotations.Api;
|
||||
//import io.swagger.annotations.ApiImplicitParam;
|
||||
//import io.swagger.annotations.ApiImplicitParams;
|
||||
//import io.swagger.annotations.ApiOperation;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.web.bind.annotation.*;
|
||||
//
|
||||
//@Tag(name = "云端录像")
|
||||
//
|
||||
//@RestController
|
||||
//@RequestMapping("/api/record")
|
||||
//public class RecordController {
|
||||
//
|
||||
// @Autowired
|
||||
// private IRecordInfoServer recordInfoServer;
|
||||
//
|
||||
// //@ApiOperation("录像列表查询")
|
||||
// @ApiImplicitParams({
|
||||
// @ApiImplicitParam(name="page", value = "当前页", required = true, dataTypeClass = Integer.class),
|
||||
// @ApiImplicitParam(name="count", value = "每页查询数量", required = true, dataTypeClass = Integer.class),
|
||||
// @ApiImplicitParam(name="query", value = "查询内容", dataTypeClass = String.class),
|
||||
// })
|
||||
// @GetMapping(value = "/app/list")
|
||||
// @ResponseBody
|
||||
// public Object list(@RequestParam(required = false)Integer page,
|
||||
// @RequestParam(required = false)Integer count ){
|
||||
//
|
||||
// PageInfo<RecordInfo> recordList = recordInfoServer.getRecordList(page - 1, page - 1 + count);
|
||||
// return recordList;
|
||||
// }
|
||||
//
|
||||
// //@ApiOperation("获取录像详情")
|
||||
// @ApiImplicitParams({
|
||||
// @ApiImplicitParam(name="recordInfo", value = "录像记录", required = true, dataTypeClass = RecordInfo.class)
|
||||
// })
|
||||
// @GetMapping(value = "/detail")
|
||||
// @ResponseBody
|
||||
// public JSONObject list(RecordInfo recordInfo, String time ){
|
||||
//
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
//}
|
||||
@ -92,7 +92,7 @@ public class ApiStreamController {
|
||||
result.put("error","device[ " + serial + " ]未找到");
|
||||
resultDeferredResult.setResult(result);
|
||||
return resultDeferredResult;
|
||||
}else if (device.isOnLine()) {
|
||||
}else if (!device.isOnLine()) {
|
||||
JSONObject result = new JSONObject();
|
||||
result.put("error","device[ " + code + " ]offline");
|
||||
resultDeferredResult.setResult(result);
|
||||
|
||||
@ -34,6 +34,19 @@ spring:
|
||||
poolMaxWait: 5
|
||||
# [必选] jdbc数据库配置
|
||||
datasource:
|
||||
# kingbase配置
|
||||
# type: com.zaxxer.hikari.HikariDataSource
|
||||
# driver-class-name: com.kingbase8.Driver
|
||||
# url: jdbc:kingbase8://192.168.1.55:54321/wvp?useUnicode=true&characterEncoding=utf8
|
||||
# username: system
|
||||
# password: system
|
||||
# postgresql配置
|
||||
# type: com.zaxxer.hikari.HikariDataSource
|
||||
# driver-class-name: org.postgresql.Driver
|
||||
# url: jdbc:postgresql://192.168.1.242:3306/242wvp
|
||||
# username: root
|
||||
# password: SYceshizu1234
|
||||
# mysql配置
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://127.0.0.1:3306/wvp2?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true
|
||||
@ -139,6 +152,10 @@ media:
|
||||
auto-config: true
|
||||
# [可选] zlm服务器的hook.admin_params=secret
|
||||
secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
|
||||
# 录像路径
|
||||
record-path: ./www/record
|
||||
# 录像保存时长
|
||||
record-day: 7
|
||||
# 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试
|
||||
rtp:
|
||||
# [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输
|
||||
@ -182,7 +199,7 @@ user-settings:
|
||||
# 使用推流状态作为推流通道状态
|
||||
use-pushing-as-status: true
|
||||
# 使用来源请求ip作为streamIp,当且仅当你只有zlm节点它与wvp在一起的情况下开启
|
||||
use-source-ip-as-stream-ip: true
|
||||
use-source-ip-as-stream-ip: false
|
||||
# 国标点播 按需拉流, true:有人观看拉流,无人观看释放, false:拉起后不自动释放
|
||||
stream-on-demand: true
|
||||
# 推流鉴权, 默认开启
|
||||
|
||||
@ -10,7 +10,6 @@ const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
const portfinder = require('portfinder')
|
||||
|
||||
const HOST = process.env.HOST
|
||||
const PORT = process.env.PORT && Number(process.env.PORT)
|
||||
|
||||
const devWebpackConfig = merge(baseWebpackConfig, {
|
||||
@ -31,9 +30,8 @@ const devWebpackConfig = merge(baseWebpackConfig, {
|
||||
hot: true,
|
||||
contentBase: false, // since we use CopyWebpackPlugin.
|
||||
compress: true,
|
||||
host: HOST || config.dev.host,
|
||||
// host:'127.0.0.1',
|
||||
port: PORT || config.dev.port,
|
||||
host: config.dev.host,
|
||||
port: config.dev.port,
|
||||
open: config.dev.autoOpenBrowser,
|
||||
overlay: config.dev.errorOverlay
|
||||
? { warnings: false, errors: true }
|
||||
|
||||
19813
web_src/package-lock.json
generated
19813
web_src/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,207 +1,281 @@
|
||||
<template>
|
||||
<div id="app" style="width: 100%">
|
||||
<div id="app" style="width: 100%">
|
||||
<div class="page-header">
|
||||
<div class="page-title">
|
||||
<el-page-header v-if="recordDetail" @back="backToList" content="云端录像"></el-page-header>
|
||||
<div v-if="!recordDetail">云端录像</div>
|
||||
<div >云端录像</div>
|
||||
</div>
|
||||
|
||||
<div class="page-header-btn">
|
||||
搜索:
|
||||
<el-input @input="getMediaServerList" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
|
||||
prefix-icon="el-icon-search" v-model="search" clearable></el-input>
|
||||
开始时间:
|
||||
<el-date-picker
|
||||
v-model="startTime"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
@change="getMediaServerList"
|
||||
placeholder="选择日期时间">
|
||||
</el-date-picker>
|
||||
结束时间:
|
||||
<el-date-picker
|
||||
v-model="endTime"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
@change="getMediaServerList"
|
||||
placeholder="选择日期时间">
|
||||
</el-date-picker>
|
||||
节点选择:
|
||||
<el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServerId" placeholder="请选择" :disabled="recordDetail">
|
||||
<el-select size="mini" @change="getMediaServerList" style="width: 16rem; margin-right: 1rem;"
|
||||
v-model="mediaServerId" placeholder="请选择" >
|
||||
<el-option label="全部" value=""></el-option>
|
||||
<el-option
|
||||
v-for="item in mediaServerList"
|
||||
:key="item.id"
|
||||
:label="item.id"
|
||||
:value="item.id">
|
||||
v-for="item in mediaServerList"
|
||||
:key="item.id"
|
||||
:label="item.id"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-button v-if="!recordDetail" icon="el-icon-refresh-right" circle size="mini" :loading="loading" @click="getRecordList()"></el-button>
|
||||
<!-- <el-button size="mini" icon="el-icon-delete" type="danger" @click="deleteRecord()">批量删除</el-button>-->
|
||||
<el-button icon="el-icon-refresh-right" circle size="mini" :loading="loading"
|
||||
@click="getRecordList()"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!recordDetail">
|
||||
|
||||
<!--设备列表-->
|
||||
<el-table :data="recordList" style="width: 100%" :height="winHeight">
|
||||
<el-table-column prop="app" label="应用名" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="stream" label="流ID" >
|
||||
</el-table-column>
|
||||
<el-table-column prop="time" label="时间" >
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="360" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="medium" icon="el-icon-folder-opened" type="text" @click="showRecordDetail(scope.row)">查看</el-button>
|
||||
<!-- <el-button size="mini" icon="el-icon-delete" type="danger" @click="deleteRecord(scope.row)">删除</el-button>-->
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="float: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
<!--设备列表-->
|
||||
<el-table :data="recordList" style="width: 100%" :height="winHeight">
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55">
|
||||
</el-table-column>
|
||||
<el-table-column prop="app" label="应用名">
|
||||
</el-table-column>
|
||||
<el-table-column prop="stream" label="流ID" width="380">
|
||||
</el-table-column>
|
||||
<el-table-column label="开始时间">
|
||||
<template slot-scope="scope">
|
||||
{{formatTimeStamp(scope.row.startTime)}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="结束时间">
|
||||
<template slot-scope="scope">
|
||||
{{formatTimeStamp(scope.row.endTime)}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="时长">
|
||||
<template slot-scope="scope">
|
||||
<el-tag>{{formatTime(scope.row.timeLen)}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="fileName" label="文件名称">
|
||||
</el-table-column>
|
||||
<el-table-column prop="mediaServerId" label="流媒体">
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="medium" icon="el-icon-video-play" type="text" @click="play(scope.row)">播放
|
||||
</el-button>
|
||||
<!-- <el-button size="medium" icon="el-icon-delete" type="text" style="color: #f56c6c"-->
|
||||
<!-- @click="deleteRecord(scope.row)">删除-->
|
||||
<!-- </el-button>-->
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
style="float: right"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="currentChange"
|
||||
:current-page="currentPage"
|
||||
:page-size="count"
|
||||
:page-sizes="[15, 25, 35, 50]"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
:total="total">
|
||||
</el-pagination>
|
||||
<el-dialog
|
||||
:title="playerTitle"
|
||||
:visible.sync="showPlayer"
|
||||
width="50%">
|
||||
<easyPlayer ref="recordVideoPlayer" :videoUrl="videoUrl" :height="false" ></easyPlayer>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import MediaServer from './service/MediaServer'
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
uiHeader
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mediaServerList: [], // 滅体节点列表
|
||||
mediaServerId: null, // 媒体服务
|
||||
mediaServerPath: null, // 媒体服务地址
|
||||
recordList: [], // 设备列表
|
||||
chooseRecord: null, // 媒体服务
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import MediaServer from './service/MediaServer'
|
||||
import easyPlayer from './common/easyPlayer.vue'
|
||||
import moment from 'moment'
|
||||
import axios from "axios";
|
||||
|
||||
updateLooper: 0, //数据刷新轮训标志
|
||||
winHeight: window.innerHeight - 250,
|
||||
currentPage:1,
|
||||
count:15,
|
||||
total:0,
|
||||
loading: false,
|
||||
mediaServerObj : new MediaServer(),
|
||||
recordDetail: false
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
uiHeader,easyPlayer
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
search: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
showPlayer: false,
|
||||
playerTitle: '',
|
||||
videoUrl: '',
|
||||
playerStyle: {
|
||||
"margin": "auto",
|
||||
"margin-bottom": "20px",
|
||||
"width": window.innerWidth/2 + "px",
|
||||
"height": this.winHeight/2 + "px",
|
||||
},
|
||||
mediaServerList: [], // 滅体节点列表
|
||||
mediaServerId: "", // 媒体服务
|
||||
mediaServerPath: null, // 媒体服务地址
|
||||
recordList: [], // 设备列表
|
||||
chooseRecord: null, // 媒体服务
|
||||
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
updateLooper: 0, //数据刷新轮训标志
|
||||
winHeight: window.innerHeight - 250,
|
||||
currentPage: 1,
|
||||
count: 15,
|
||||
total: 0,
|
||||
loading: false,
|
||||
mediaServerObj: new MediaServer(),
|
||||
|
||||
},
|
||||
mounted() {
|
||||
this.initData();
|
||||
},
|
||||
destroyed() {
|
||||
// this.$destroy('videojs');
|
||||
},
|
||||
methods: {
|
||||
initData: function() {
|
||||
// 获取媒体节点列表
|
||||
this.getMediaServerList();
|
||||
// this.getRecordList();
|
||||
},
|
||||
currentChange: function(val){
|
||||
this.currentPage = val;
|
||||
this.getRecordList();
|
||||
},
|
||||
handleSizeChange: function(val){
|
||||
this.count = val;
|
||||
this.getRecordList();
|
||||
},
|
||||
getMediaServerList: function (){
|
||||
let that = this;
|
||||
that.mediaServerObj.getOnlineMediaServerList((data)=>{
|
||||
that.mediaServerList = data.data;
|
||||
if (that.mediaServerList.length > 0) {
|
||||
that.mediaServerId = that.mediaServerList[0].id
|
||||
that.setMediaServerPath(that.mediaServerId);
|
||||
that.getRecordList();
|
||||
}
|
||||
})
|
||||
},
|
||||
setMediaServerPath: function (serverId) {
|
||||
let that = this;
|
||||
let i;
|
||||
for (i = 0; i < that.mediaServerList.length; i++) {
|
||||
if (serverId === that.mediaServerList[i].id) {
|
||||
break;
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {},
|
||||
mounted() {
|
||||
this.initData();
|
||||
},
|
||||
destroyed() {
|
||||
this.$destroy('recordVideoPlayer');
|
||||
},
|
||||
methods: {
|
||||
initData: function () {
|
||||
// 获取媒体节点列表
|
||||
this.getMediaServerList();
|
||||
this.getRecordList();
|
||||
},
|
||||
currentChange: function (val) {
|
||||
this.currentPage = val;
|
||||
this.getRecordList();
|
||||
},
|
||||
handleSizeChange: function (val) {
|
||||
this.count = val;
|
||||
this.getRecordList();
|
||||
},
|
||||
getMediaServerList: function () {
|
||||
let that = this;
|
||||
that.mediaServerObj.getOnlineMediaServerList((data) => {
|
||||
that.mediaServerList = data.data;
|
||||
})
|
||||
},
|
||||
setMediaServerPath: function (serverId) {
|
||||
let that = this;
|
||||
let i;
|
||||
for (i = 0; i < that.mediaServerList.length; i++) {
|
||||
if (serverId === that.mediaServerList[i].id) {
|
||||
break;
|
||||
}
|
||||
let port = that.mediaServerList[i].httpPort;
|
||||
if (location.protocol === "https:" && that.mediaServerList[i].httpSSlPort) {
|
||||
port = that.mediaServerList[i].httpSSlPort
|
||||
}
|
||||
let port = that.mediaServerList[i].httpPort;
|
||||
if (location.protocol === "https:" && that.mediaServerList[i].httpSSlPort) {
|
||||
port = that.mediaServerList[i].httpSSlPort
|
||||
}
|
||||
that.mediaServerPath = location.protocol + "//" + that.mediaServerList[i].streamIp + ":" + port
|
||||
console.log(that.mediaServerPath)
|
||||
},
|
||||
getRecordList: function () {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/list`,
|
||||
params: {
|
||||
app: '',
|
||||
stream: '',
|
||||
query: this.search,
|
||||
startTime: this.startTime,
|
||||
endTime: this.endTime,
|
||||
mediaServerId: this.mediaServerId,
|
||||
page: this.currentPage,
|
||||
count: this.count
|
||||
}
|
||||
that.mediaServerPath = location.protocol + "//" + that.mediaServerList[i].streamIp + ":" + port
|
||||
console.log(that.mediaServerPath)
|
||||
},
|
||||
getRecordList: function (){
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/record_proxy/${that.mediaServerId}/api/record/list`,
|
||||
params: {
|
||||
page: that.currentPage,
|
||||
count: that.count
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
if (res.data.code === 0) {
|
||||
this.total = res.data.data.total;
|
||||
this.recordList = res.data.data.list;
|
||||
}
|
||||
this.loading = false;
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
play(row) {
|
||||
console.log(row)
|
||||
this.chooseRecord = row;
|
||||
this.showPlayer = true;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url: `/api/cloud/record/play/path`,
|
||||
params: {
|
||||
recordId: row.id,
|
||||
}
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
if (res.data.code === 0) {
|
||||
if (location.protocol === "https:") {
|
||||
this.videoUrl = res.data.data.httpsPath;
|
||||
}else {
|
||||
this.videoUrl = res.data.data.httpPath;
|
||||
}
|
||||
}).then(function (res) {
|
||||
console.log(res)
|
||||
if (res.data.code === 0) {
|
||||
that.total = res.data.data.total;
|
||||
that.recordList = res.data.data.list;
|
||||
console.log(222 )
|
||||
console.log(this.videoUrl )
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
getFileBasePath(item) {
|
||||
let basePath = ""
|
||||
if (axios.defaults.baseURL.startsWith("http")) {
|
||||
basePath = `${axios.defaults.baseURL}/record_proxy/${item.mediaServerId}`
|
||||
}else {
|
||||
basePath = `${window.location.origin}${axios.defaults.baseURL}/record_proxy/${item.mediaServerId}`
|
||||
}
|
||||
that.loading = false;
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
that.loading = false;
|
||||
});
|
||||
},
|
||||
backToList(){
|
||||
this.recordDetail= false;
|
||||
},
|
||||
chooseMediaChange(val){
|
||||
console.log(val)
|
||||
this.total = 0;
|
||||
this.recordList = [];
|
||||
this.setMediaServerPath(val);
|
||||
this.getRecordList();
|
||||
},
|
||||
showRecordDetail(row){
|
||||
this.recordDetail = true;
|
||||
this.chooseRecord = row;
|
||||
// 查询是否存在录像
|
||||
// this.$axios({
|
||||
// method: 'delete',
|
||||
// url:`/record_proxy/api/record/delete`,
|
||||
// params: {
|
||||
// page: this.currentPage,
|
||||
// count: this.count
|
||||
// }
|
||||
// }).then((res) => {
|
||||
// console.log(res)
|
||||
// this.total = res.data.data.total;
|
||||
// this.recordList = res.data.data.list;
|
||||
// }).catch(function (error) {
|
||||
// console.log(error);
|
||||
// });
|
||||
this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`)
|
||||
},
|
||||
deleteRecord(){
|
||||
// TODO
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'delete',
|
||||
url:`/record_proxy/api/record/delete`,
|
||||
params: {
|
||||
page: that.currentPage,
|
||||
count: that.count
|
||||
}
|
||||
}).then(function (res) {
|
||||
console.log(res)
|
||||
if (res.data.code === 0) {
|
||||
that.total = res.data.data.total;
|
||||
that.recordList = res.data.data.list;
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
return basePath;
|
||||
},
|
||||
deleteRecord() {
|
||||
// TODO
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'delete',
|
||||
url: `/record_proxy/api/record/delete`,
|
||||
params: {
|
||||
page: that.currentPage,
|
||||
count: that.count
|
||||
}
|
||||
}).then(function (res) {
|
||||
console.log(res)
|
||||
if (res.data.code === 0) {
|
||||
that.total = res.data.data.total;
|
||||
that.recordList = res.data.data.list;
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
formatTime(time) {
|
||||
const h = parseInt(time / 3600)
|
||||
const minute = parseInt(time / 60 % 60)
|
||||
const second = Math.ceil(time % 60)
|
||||
|
||||
return (h > 0 ? h + `小时` : '') + (minute > 0 ? minute + '分' : '') + second + '秒'
|
||||
},
|
||||
formatTimeStamp(time) {
|
||||
return moment.unix(time).format('yyyy-MM-DD HH:mm:ss')
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@ -37,13 +37,13 @@
|
||||
<div class="record-list-box" :style="recordListStyle">
|
||||
<ul v-if="detailFiles.length >0" class="infinite-list record-list" v-infinite-scroll="infiniteScroll" >
|
||||
<li v-for="(item,index) in detailFiles" :key="index" class="infinite-list-item record-list-item" >
|
||||
<el-tag v-if="choosedFile !== item.filename" @click="chooseFile(item)">
|
||||
<el-tag v-if="choosedFile !== item.fileName" @click="chooseFile(item)">
|
||||
<i class="el-icon-video-camera" ></i>
|
||||
{{ getFileShowName(item.fileName) }}
|
||||
{{ getFileShowName(item) }}
|
||||
</el-tag>
|
||||
<el-tag type="danger" v-if="choosedFile === item.filename">
|
||||
<el-tag type="danger" v-if="choosedFile === item.fileName">
|
||||
<i class="el-icon-video-camera" ></i>
|
||||
{{ getFileShowName(item.fileName) }}
|
||||
{{ getFileShowName(item) }}
|
||||
</el-tag>
|
||||
<a class="el-icon-download" style="color: #409EFF;font-weight: 600;margin-left: 10px;"
|
||||
:href="`${getFileBasePath(item)}/download.html?url=download/${app}/${stream}/${chooseDate}/${item.fileName}`"
|
||||
@ -135,7 +135,7 @@
|
||||
<script>
|
||||
// TODO 根据查询的时间列表设置滑轨的最大值与最小值,
|
||||
import uiHeader from '../layout/UiHeader.vue'
|
||||
import player from './dialog/easyPlayer.vue'
|
||||
import player from './common/easyPlayer.vue'
|
||||
import moment from 'moment'
|
||||
import axios from "axios";
|
||||
export default {
|
||||
@ -319,7 +319,7 @@
|
||||
this.choosedFile = "";
|
||||
}else {
|
||||
this.choosedFile = file.fileName;
|
||||
this.videoUrl = `${this.getFileBasePath(file)}/download/${this.app}/${this.stream}/${this.chooseDate}/${this.choosedFile}`
|
||||
this.videoUrl = `${this.getFileBasePath(file)}/download/${this.app}/${this.stream}/${this.chooseDate}/${file.fileName}`
|
||||
console.log(this.videoUrl)
|
||||
}
|
||||
|
||||
@ -327,9 +327,8 @@
|
||||
backToList() {
|
||||
this.$router.back()
|
||||
},
|
||||
getFileShowName(name) {
|
||||
return name.substring(0, 2) + ":" + name.substring(2, 4) + ":" + name.substring(4, 6) + "-" +
|
||||
name.substring(7, 9) + ":" + name.substring(9, 11) + ":" + name.substring(11, 13)
|
||||
getFileShowName(item) {
|
||||
return moment.unix(item.startTime).format('HH:mm:ss') + "-" + moment.unix(item.endTime).format('HH:mm:ss')
|
||||
},
|
||||
chooseMediaChange() {
|
||||
|
||||
@ -376,13 +375,8 @@
|
||||
},
|
||||
getTimeForFile(file){
|
||||
console.log(file)
|
||||
let timeStr = file.fileName.substring(0, 17);
|
||||
if(timeStr.indexOf("~") > 0){
|
||||
timeStr = timeStr.replaceAll("-",":")
|
||||
}
|
||||
let timeArr = timeStr.split("-");
|
||||
let starTime = new Date(this.chooseDate + " " + timeArr[0]);
|
||||
let endTime = new Date(this.chooseDate + " " + timeArr[1]);
|
||||
let starTime = new Date(file.startTime * 1000);
|
||||
let endTime = new Date(file.endTime * 1000);
|
||||
if(this.checkIsOver24h(starTime,endTime)){
|
||||
endTime = new Date(this.chooseDate + " " + "23:59:59");
|
||||
}
|
||||
@ -486,12 +480,13 @@
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/record_proxy/${that.mediaServerId}/api/record/file/download/task/add`,
|
||||
url:`/api/cloud/record/task/add`,
|
||||
params: {
|
||||
app: that.app,
|
||||
stream: that.stream,
|
||||
startTime: moment(this.taskTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'),
|
||||
endTime: moment(this.taskTimeRange[1]).format('YYYY-MM-DD HH:mm:ss'),
|
||||
app: this.app,
|
||||
stream: this.stream,
|
||||
mediaServerId: this.mediaServerId,
|
||||
startTime: moment(this.taskTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'),
|
||||
endTime: moment(this.taskTimeRange[1]).format('YYYY-MM-DD HH:mm:ss'),
|
||||
}
|
||||
}).then(function (res) {
|
||||
if (res.data.code === 0 ) {
|
||||
@ -511,8 +506,9 @@
|
||||
let that = this;
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/record_proxy/${that.mediaServerId}/api/record/file/download/task/list`,
|
||||
url:`/api/cloud/record/task/list`,
|
||||
params: {
|
||||
mediaServerId: this.mediaServerId,
|
||||
isEnd: isEnd,
|
||||
}
|
||||
}).then(function (res) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div id="easyplayer"></div>
|
||||
<div id="easyplayer" ></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -6,8 +6,7 @@
|
||||
<el-progress :percentage="percentage"></el-progress>
|
||||
</el-col>
|
||||
<el-col :span="6" >
|
||||
<el-button icon="el-icon-download" v-if="percentage < 100" size="mini" title="点击下载可将以缓存部分下载到本地" @click="download()">停止缓存并下载</el-button>
|
||||
<el-button icon="el-icon-download" v-if="downloadFile" size="mini" title="点击下载" @click="downloadFileClientEvent()">点击下载</el-button>
|
||||
<el-button icon="el-icon-download" v-if="downloadFile" size="mini" title="点击下载" @click="downloadFileClientEvent()">下载</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
@ -27,7 +26,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: "四倍速下载中...",
|
||||
title: "下载中...",
|
||||
deviceId: "",
|
||||
channelId: "",
|
||||
app: "",
|
||||
@ -39,7 +38,6 @@ export default {
|
||||
streamInfo: null,
|
||||
taskId: null,
|
||||
getProgressRun: false,
|
||||
getProgressForFileRun: false,
|
||||
timer: null,
|
||||
downloadFile: null,
|
||||
|
||||
@ -62,7 +60,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
if (this.percentage == 100 ) {
|
||||
this.getFileDownload();
|
||||
|
||||
return;
|
||||
}
|
||||
setTimeout( ()=>{
|
||||
@ -75,7 +73,6 @@ export default {
|
||||
method: 'get',
|
||||
url: `/api/gb_record/download/progress/${this.deviceId}/${this.channelId}/${this.stream}`
|
||||
}).then((res)=> {
|
||||
console.log(res)
|
||||
if (res.data.code === 0) {
|
||||
this.streamInfo = res.data.data;
|
||||
if (parseFloat(res.data.progress) == 1) {
|
||||
@ -83,6 +80,15 @@ export default {
|
||||
}else {
|
||||
this.percentage = (parseFloat(res.data.data.progress)*100).toFixed(1);
|
||||
}
|
||||
if (this.streamInfo.downLoadFilePath) {
|
||||
if (location.protocol === "https:") {
|
||||
this.downloadFile = this.streamInfo.downLoadFilePath.httpsPath;
|
||||
}else {
|
||||
this.downloadFile = this.streamInfo.downLoadFilePath.httpPath;
|
||||
}
|
||||
this.getProgressRun = false;
|
||||
this.downloadFileClientEvent()
|
||||
}
|
||||
if (callback)callback();
|
||||
}else {
|
||||
this.$message({
|
||||
@ -108,24 +114,11 @@ export default {
|
||||
}
|
||||
this.showDialog=false;
|
||||
this.getProgressRun = false;
|
||||
this.getProgressForFileRun = false;
|
||||
},
|
||||
gbScale: function (scale){
|
||||
this.scale = scale;
|
||||
},
|
||||
download: function (){
|
||||
this.getProgressRun = false;
|
||||
if (this.streamInfo != null ) {
|
||||
if (this.streamInfo.progress < 1) {
|
||||
// 发送停止缓存
|
||||
this.stopDownloadRecord((res)=>{
|
||||
this.getFileDownload()
|
||||
})
|
||||
}else {
|
||||
this.getFileDownload()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
stopDownloadRecord: function (callback) {
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
@ -134,74 +127,20 @@ export default {
|
||||
if (callback) callback(res)
|
||||
});
|
||||
},
|
||||
getFileDownload: function (){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/record_proxy/${this.mediaServerId}/api/record/file/download/task/add`,
|
||||
params: {
|
||||
app: this.app,
|
||||
stream: this.stream,
|
||||
startTime: null,
|
||||
endTime: null,
|
||||
}
|
||||
}).then((res) =>{
|
||||
if (res.data.code === 0 ) {
|
||||
// 查询进度
|
||||
this.title = "录像文件处理中..."
|
||||
this.taskId = res.data.data;
|
||||
this.percentage = 0.0;
|
||||
this.getProgressForFileRun = true;
|
||||
this.getProgressForFileTimer();
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
getProgressForFileTimer: function (){
|
||||
if (!this.getProgressForFileRun || this.percentage == 100) {
|
||||
return;
|
||||
}
|
||||
setTimeout( ()=>{
|
||||
if (!this.showDialog) return;
|
||||
this.getProgressForFile(this.getProgressForFileTimer)
|
||||
}, 1000)
|
||||
},
|
||||
getProgressForFile: function (callback){
|
||||
this.$axios({
|
||||
method: 'get',
|
||||
url:`/record_proxy/${this.mediaServerId}/api/record/file/download/task/list`,
|
||||
params: {
|
||||
app: this.app,
|
||||
stream: this.stream,
|
||||
taskId: this.taskId,
|
||||
isEnd: true,
|
||||
}
|
||||
}).then((res) => {
|
||||
console.log(res)
|
||||
if (res.data.code === 0) {
|
||||
if (res.data.data.length === 0){
|
||||
this.percentage = 0
|
||||
// 往往在多次请求后(实验五分钟的视频是三次请求),才会返回数据,第一次请求通常是返回空数组
|
||||
if (callback)callback()
|
||||
return
|
||||
}
|
||||
// res.data.data应是数组类型
|
||||
this.percentage = parseFloat(res.data.data[0].percentage)*100
|
||||
if (res.data.data[0].percentage === '1') {
|
||||
this.getProgressForFileRun = false;
|
||||
this.downloadFile = res.data.data[0].downloadFile
|
||||
this.title = "文件处理完成,点击按扭下载"
|
||||
// window.open(res.data.data[0].downloadFile)
|
||||
}else {
|
||||
if (callback)callback()
|
||||
}
|
||||
}
|
||||
}).catch(function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
},
|
||||
downloadFileClientEvent: function (){
|
||||
window.open(this.downloadFile )
|
||||
// window.open(this.downloadFile )
|
||||
|
||||
let x = new XMLHttpRequest();
|
||||
x.open("GET", this.downloadFile, true);
|
||||
x.responseType = 'blob';
|
||||
x.onload=(e)=> {
|
||||
let url = window.URL.createObjectURL(x.response)
|
||||
let a = document.createElement('a');
|
||||
a.href = url
|
||||
a.download = this.deviceId + "-" + this.channelId + ".mp4";
|
||||
a.click()
|
||||
}
|
||||
x.send();
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
|
||||
63
打包/config/assist-application.yml
Executable file
63
打包/config/assist-application.yml
Executable file
@ -0,0 +1,63 @@
|
||||
spring:
|
||||
# REDIS数据库配置
|
||||
redis:
|
||||
# [可选] 超时时间
|
||||
timeout: 10000
|
||||
# 以下为单机配置
|
||||
# [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1
|
||||
host: 127.0.0.1
|
||||
# [必须修改] 端口号
|
||||
port: 6379
|
||||
# [可选] 数据库 DB
|
||||
database: 1
|
||||
# [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
|
||||
password: adminadmin123.
|
||||
# 以下为集群配置
|
||||
# cluster:
|
||||
# nodes: 192.168.1.242:7001
|
||||
# password: 4767cb971b40a1300fa09b7f87b09d1c
|
||||
|
||||
# [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
|
||||
server:
|
||||
port: 18081
|
||||
# [可选] HTTPS配置, 默认不开启
|
||||
ssl:
|
||||
# [可选] 是否开启HTTPS访问
|
||||
enabled: false
|
||||
# [可选] 证书文件路径,放置在resource/目录下即可,修改xxx为文件名
|
||||
key-store: classpath:xxx.jks
|
||||
# [可选] 证书密码
|
||||
key-password: password
|
||||
# [可选] 证书类型, 默认为jks,根据实际修改
|
||||
key-store-type: JKS
|
||||
|
||||
# [根据业务需求配置]
|
||||
userSettings:
|
||||
# [必选 ] 服务ID
|
||||
id: 334533
|
||||
# [可选 ] 录像下载合成临时文件保存时长, 不配置默认取值recordDay(单位: 天)每天晚12点自动对过期文件执行清理
|
||||
# recordTempDay: 7
|
||||
# [必选 ] ffmpeg路径
|
||||
ffmpeg: lib/ffmpeg
|
||||
# [必选 ] ffprobe路径, 一般安装ffmpeg就会自带, 一般跟ffmpeg在同一目录,用于查询文件的信息
|
||||
ffprobe: lib/ffprobe
|
||||
# [可选 ] 限制 ffmpeg 合并文件使用的线程数,间接限制cpu使用率, 默认2 限制到50%
|
||||
threads: 2
|
||||
|
||||
swagger-ui:
|
||||
enabled: true
|
||||
# [可选] 日志配置, 一般不需要改
|
||||
logging:
|
||||
file:
|
||||
name: logs/wvp.log
|
||||
max-history: 30
|
||||
max-size: 10MB
|
||||
total-size-cap: 300MB
|
||||
level:
|
||||
root: WARN
|
||||
top:
|
||||
panll:
|
||||
assist: info
|
||||
net:
|
||||
bramp:
|
||||
ffmpeg: error
|
||||
166
打包/config/config.ini
Executable file
166
打包/config/config.ini
Executable file
@ -0,0 +1,166 @@
|
||||
; auto-generated by mINI class {
|
||||
|
||||
[api]
|
||||
apiDebug=1
|
||||
defaultSnap=./www/logo.png
|
||||
secret=034523TF8yT83wh5Wvz73f7
|
||||
snapRoot=./www/snap/
|
||||
|
||||
[cluster]
|
||||
origin_url=
|
||||
retry_count=3
|
||||
timeout_sec=15
|
||||
|
||||
[ffmpeg]
|
||||
bin=/usr/bin/ffmpeg
|
||||
cmd=%s -re -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s
|
||||
log=./ffmpeg/ffmpeg.log
|
||||
restart_sec=0
|
||||
snap=%s -i %s -y -f mjpeg -t 0.001 %s
|
||||
|
||||
[general]
|
||||
check_nvidia_dev=1
|
||||
enableVhost=0
|
||||
enable_ffmpeg_log=0
|
||||
flowThreshold=1024
|
||||
maxStreamWaitMS=15000
|
||||
mediaServerId=GQ3TF8yT83wh5Wvz
|
||||
mergeWriteMS=0
|
||||
resetWhenRePlay=1
|
||||
streamNoneReaderDelayMS=15000
|
||||
unready_frame_cache=100
|
||||
wait_add_track_ms=3000
|
||||
wait_track_ready_ms=10000
|
||||
|
||||
[hls]
|
||||
broadcastRecordTs=0
|
||||
deleteDelaySec=10
|
||||
fileBufSize=65536
|
||||
segDur=2
|
||||
segKeep=0
|
||||
segNum=3
|
||||
segRetain=5
|
||||
|
||||
[hook]
|
||||
admin_params=secret=034523TF8yT83wh5Wvz73f7
|
||||
alive_interval=30.000000
|
||||
enable=1
|
||||
on_flow_report=
|
||||
on_http_access=
|
||||
on_play=http://192.168.1.3:18082/index/hook/on_play
|
||||
on_publish=http://192.168.1.3:18082/index/hook/on_publish
|
||||
on_record_mp4=
|
||||
on_record_ts=
|
||||
on_rtp_server_timeout=http://192.168.1.3:18082/index/hook/on_rtp_server_timeout
|
||||
on_rtsp_auth=
|
||||
on_rtsp_realm=
|
||||
on_send_rtp_stopped=http://192.168.1.3:18082/index/hook/on_send_rtp_stopped
|
||||
on_server_keepalive=http://192.168.1.3:18082/index/hook/on_server_keepalive
|
||||
on_server_started=http://192.168.1.3:18082/index/hook/on_server_started
|
||||
on_shell_login=
|
||||
on_stream_changed=http://192.168.1.3:18082/index/hook/on_stream_changed
|
||||
on_stream_none_reader=http://192.168.1.3:18082/index/hook/on_stream_none_reader
|
||||
on_stream_not_found=http://192.168.1.3:18082/index/hook/on_stream_not_found
|
||||
retry=1
|
||||
retry_delay=3.000000
|
||||
timeoutSec=20
|
||||
|
||||
[http]
|
||||
charSet=utf-8
|
||||
dirMenu=1
|
||||
forbidCacheSuffix=
|
||||
forwarded_ip_header=
|
||||
keepAliveSecond=15
|
||||
maxReqSize=40960
|
||||
notFound=<html><head><title>404 Not Found</title></head><body bgcolor="white"><center><h1>您访问的资源不存在!</h1></center><hr><center>ZLMediaKit(git hash:f6cba98/2023-02-06T14:18:21+08:00,branch:master,build time:2023-02-07T10:51:47)</center></body></html>
|
||||
port=6080
|
||||
rootPath=./www
|
||||
sendBufSize=65536
|
||||
sslport=16080
|
||||
virtualPath=
|
||||
|
||||
[multicast]
|
||||
addrMax=239.255.255.255
|
||||
addrMin=239.0.0.0
|
||||
udpTTL=64
|
||||
|
||||
[protocol]
|
||||
add_mute_audio=1
|
||||
continue_push_ms=3000
|
||||
enable_audio=1
|
||||
enable_fmp4=1
|
||||
enable_hls=1
|
||||
enable_mp4=0
|
||||
enable_rtmp=1
|
||||
enable_rtsp=1
|
||||
enable_ts=1
|
||||
fmp4_demand=0
|
||||
hls_demand=0
|
||||
hls_save_path=./www
|
||||
modify_stamp=0
|
||||
mp4_as_player=0
|
||||
mp4_max_second=3600
|
||||
mp4_save_path=./www
|
||||
rtmp_demand=0
|
||||
rtsp_demand=0
|
||||
ts_demand=0
|
||||
|
||||
[record]
|
||||
appName=record
|
||||
fastStart=0
|
||||
fileBufSize=65536
|
||||
fileRepeat=0
|
||||
sampleMS=500
|
||||
|
||||
[rtc]
|
||||
externIP=192.168.1.3
|
||||
port=8000
|
||||
preferredCodecA=PCMA,PCMU,opus,mpeg4-generic
|
||||
preferredCodecV=H264,H265,AV1,VP9,VP8
|
||||
rembBitRate=0
|
||||
tcpPort=8000
|
||||
timeoutSec=15
|
||||
|
||||
[rtmp]
|
||||
handshakeSecond=15
|
||||
keepAliveSecond=15
|
||||
modifyStamp=0
|
||||
port=1935
|
||||
sslport=19350
|
||||
|
||||
[rtp]
|
||||
audioMtuSize=600
|
||||
lowLatency=0
|
||||
rtpMaxSize=10
|
||||
videoMtuSize=1400
|
||||
|
||||
[rtp_proxy]
|
||||
dumpDir=
|
||||
h264_pt=98
|
||||
h265_pt=99
|
||||
opus_pt=100
|
||||
port=10000
|
||||
port_range=40000-40500
|
||||
ps_pt=96
|
||||
timeoutSec=15
|
||||
|
||||
[rtsp]
|
||||
authBasic=0
|
||||
directProxy=1
|
||||
handshakeSecond=15
|
||||
keepAliveSecond=15
|
||||
lowLatency=0
|
||||
port=10554
|
||||
sslport=
|
||||
|
||||
[shell]
|
||||
maxReqSize=1024
|
||||
port=9000
|
||||
|
||||
[srt]
|
||||
latencyMul=4
|
||||
pktBufSize=8192
|
||||
port=9000
|
||||
timeoutSec=5
|
||||
|
||||
; } ---
|
||||
120
打包/config/wvp-application.yml
Executable file
120
打包/config/wvp-application.yml
Executable file
@ -0,0 +1,120 @@
|
||||
spring:
|
||||
# [可选]上传文件大小限制
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 10MB
|
||||
max-request-size: 100MB
|
||||
# REDIS数据库配置
|
||||
redis:
|
||||
# [可选] 超时时间
|
||||
timeout: 10000
|
||||
# 以下为单机配置
|
||||
# [必须修改] Redis服务器IP, REDIS安装在本机的,使用127.0.0.1
|
||||
host: 127.0.0.1
|
||||
# # [必须修改] 端口号
|
||||
port: 6379
|
||||
# [可选] 数据库 DB
|
||||
database: 1
|
||||
# [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
|
||||
password: adminadmin123.
|
||||
# 以下为集群配置
|
||||
# cluster:
|
||||
# nodes: 192.168.1.66:9001,192.168.1.66:9002,192.168.1.66:9003,192.168.1.66:9004,192.168.1.66:9005,192.168.1.66:9006
|
||||
# password: adminadmin123.
|
||||
# [可选] jdbc数据库配置, 项目使用sqlite作为数据库,一般不需要配置
|
||||
# mysql数据源
|
||||
datasource:
|
||||
# kingbase配置
|
||||
# type: com.zaxxer.hikari.HikariDataSource
|
||||
# driver-class-name: com.kingbase8.Driver
|
||||
# url: jdbc:kingbase8://192.168.1.55:54321/wvp?useUnicode=true&characterEncoding=utf8
|
||||
# username: system
|
||||
# password: system
|
||||
# postgresql配置
|
||||
# type: com.zaxxer.hikari.HikariDataSource
|
||||
# driver-class-name: org.postgresql.Driver
|
||||
# url: jdbc:postgresql://192.168.1.242:3306/242wvp
|
||||
# username: root
|
||||
# password: SYceshizu1234
|
||||
# mysql配置
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://192.168.1.242:3306/242wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: SYceshizu1234
|
||||
|
||||
|
||||
# kingbase 和 postgresql需要开启这个配置
|
||||
#pagehelper:
|
||||
# helper-dialect: postgresql
|
||||
|
||||
#[可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
|
||||
server:
|
||||
port: 18080
|
||||
|
||||
# 作为28181服务器的配置
|
||||
sip:
|
||||
# [必须修改] 本机的IP
|
||||
ip: 192.168.1.3
|
||||
# [可选] 28181服务监听的端口
|
||||
port: 15060
|
||||
# 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007)
|
||||
# 后两位为行业编码,定义参照附录D.3
|
||||
# 3701020049标识山东济南历下区 信息行业接入
|
||||
# [可选]
|
||||
domain: 3402000001
|
||||
# [可选]
|
||||
id: 34020000013000000001
|
||||
# [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验
|
||||
password: 12345678
|
||||
|
||||
#zlm 默认服务器配置
|
||||
media:
|
||||
# [必须修改] zlm服务器唯一id,用于触发hook时区别是哪台服务器,general.mediaServerId
|
||||
id: GQ3TF8yT83wh5Wvz
|
||||
# [必须修改] zlm服务器的内网IP
|
||||
ip: 192.168.1.3
|
||||
# [必须修改] zlm服务器的http.port
|
||||
http-port: 6080
|
||||
# [可选] zlm服务器的hook.admin_params=secret
|
||||
secret: 034523TF8yT83wh5Wvz73f7
|
||||
# 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试
|
||||
rtp:
|
||||
# [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输
|
||||
enable: true
|
||||
# [可选] 在此范围内选择端口用于媒体流传输,
|
||||
port-range: 30000,30500 # 端口范围
|
||||
# [可选] 国标级联在此范围内选择端口发送媒体流,请不要与收流端口范围重合
|
||||
send-port-range: 50502,50506 # 端口范围
|
||||
# 录像辅助服务, 部署此服务可以实现zlm录像的管理与下载, 0 表示不使用
|
||||
record-assist-port: 18089
|
||||
# 录像路径
|
||||
record-path: ./www/record
|
||||
# 录像保存时长
|
||||
record-day: 7
|
||||
# [可选] 日志配置, 一般不需要改
|
||||
logging:
|
||||
config: classpath:logback-spring-local.xml
|
||||
|
||||
# [根据业务需求配置]
|
||||
user-settings:
|
||||
server-id: 741266
|
||||
auto-apply-play: true
|
||||
interface-authentication: true
|
||||
interface-authentication-excludes:
|
||||
- /api/v1/**
|
||||
- /api/media/stream_info_by_app_and_stream
|
||||
- /api/v1/control/ptz
|
||||
- /api/cloud/record/*/**
|
||||
# 推流直播是否录制
|
||||
record-push-live: true
|
||||
# 国标是否录制
|
||||
record-sip: false
|
||||
# 使用推流状态作为推流通道状态
|
||||
use-pushing-as-status: false
|
||||
# 设备上线时是否自动同步通道
|
||||
sync-channel-on-device-online: false
|
||||
# 消息通道功能-缺少国标ID是否给所有上级发送消息
|
||||
send-to-platforms-when-id-lost: false
|
||||
|
||||
|
||||
@ -120,7 +120,7 @@ alter table device_channel
|
||||
change status status bool default false;
|
||||
|
||||
alter table device_channel
|
||||
change streamId stream_id varchar(50) null;
|
||||
change streamId stream_id varchar(255) null;
|
||||
|
||||
alter table device_channel
|
||||
change deviceId device_id varchar(50) not null;
|
||||
322
数据库/初始化-mysql-2.6.9.sql
Normal file
322
数据库/初始化-mysql-2.6.9.sql
Normal file
@ -0,0 +1,322 @@
|
||||
/*建表*/
|
||||
create table wvp_device (
|
||||
id serial primary key ,
|
||||
device_id character varying(50) not null ,
|
||||
name character varying(255),
|
||||
manufacturer character varying(255),
|
||||
model character varying(255),
|
||||
firmware character varying(255),
|
||||
transport character varying(50),
|
||||
stream_mode character varying(50),
|
||||
on_line bool default false,
|
||||
register_time character varying(50),
|
||||
keepalive_time character varying(50),
|
||||
ip character varying(50),
|
||||
create_time character varying(50),
|
||||
update_time character varying(50),
|
||||
port integer,
|
||||
expires integer,
|
||||
subscribe_cycle_for_catalog integer DEFAULT 0,
|
||||
subscribe_cycle_for_mobile_position integer DEFAULT 0,
|
||||
mobile_position_submission_interval integer DEFAULT 5,
|
||||
subscribe_cycle_for_alarm integer DEFAULT 0,
|
||||
host_address character varying(50),
|
||||
charset character varying(50),
|
||||
ssrc_check bool default false,
|
||||
geo_coord_sys character varying(50),
|
||||
media_server_id character varying(50),
|
||||
custom_name character varying(255),
|
||||
sdp_ip character varying(50),
|
||||
local_ip character varying(50),
|
||||
password character varying(255),
|
||||
as_message_channel bool default false,
|
||||
keepalive_interval_time integer,
|
||||
switch_primary_sub_stream bool default false,
|
||||
broadcast_push_after_ack bool default false,
|
||||
constraint uk_device_device unique (device_id)
|
||||
);
|
||||
|
||||
create table wvp_device_alarm (
|
||||
id serial primary key ,
|
||||
device_id character varying(50) not null,
|
||||
channel_id character varying(50) not null,
|
||||
alarm_priority character varying(50),
|
||||
alarm_method character varying(50),
|
||||
alarm_time character varying(50),
|
||||
alarm_description character varying(255),
|
||||
longitude double precision,
|
||||
latitude double precision,
|
||||
alarm_type character varying(50),
|
||||
create_time character varying(50) not null
|
||||
);
|
||||
|
||||
create table wvp_device_channel (
|
||||
id serial primary key ,
|
||||
channel_id character varying(50) not null,
|
||||
name character varying(255),
|
||||
custom_name character varying(255),
|
||||
manufacture character varying(50),
|
||||
model character varying(50),
|
||||
owner character varying(50),
|
||||
civil_code character varying(50),
|
||||
block character varying(50),
|
||||
address character varying(50),
|
||||
parent_id character varying(50),
|
||||
safety_way integer,
|
||||
register_way integer,
|
||||
cert_num character varying(50),
|
||||
certifiable integer,
|
||||
err_code integer,
|
||||
end_time character varying(50),
|
||||
secrecy character varying(50),
|
||||
ip_address character varying(50),
|
||||
port integer,
|
||||
password character varying(255),
|
||||
ptz_type integer,
|
||||
custom_ptz_type integer,
|
||||
status bool default false,
|
||||
longitude double precision,
|
||||
custom_longitude double precision,
|
||||
latitude double precision,
|
||||
custom_latitude double precision,
|
||||
stream_id character varying(255),
|
||||
device_id character varying(50) not null,
|
||||
parental character varying(50),
|
||||
has_audio bool default false,
|
||||
create_time character varying(50) not null,
|
||||
update_time character varying(50) not null,
|
||||
sub_count integer,
|
||||
longitude_gcj02 double precision,
|
||||
latitude_gcj02 double precision,
|
||||
longitude_wgs84 double precision,
|
||||
latitude_wgs84 double precision,
|
||||
business_group_id character varying(50),
|
||||
gps_time character varying(50),
|
||||
constraint uk_wvp_device_channel_unique_device_channel unique (device_id, channel_id)
|
||||
);
|
||||
|
||||
create table wvp_device_mobile_position (
|
||||
id serial primary key,
|
||||
device_id character varying(50) not null,
|
||||
channel_id character varying(50) not null,
|
||||
device_name character varying(255),
|
||||
time character varying(50),
|
||||
longitude double precision,
|
||||
latitude double precision,
|
||||
altitude double precision,
|
||||
speed double precision,
|
||||
direction double precision,
|
||||
report_source character varying(50),
|
||||
longitude_gcj02 double precision,
|
||||
latitude_gcj02 double precision,
|
||||
longitude_wgs84 double precision,
|
||||
latitude_wgs84 double precision,
|
||||
create_time character varying(50)
|
||||
);
|
||||
|
||||
create table wvp_gb_stream (
|
||||
gb_stream_id serial primary key,
|
||||
app character varying(255) not null,
|
||||
stream character varying(255) not null,
|
||||
gb_id character varying(50) not null,
|
||||
name character varying(255),
|
||||
longitude double precision,
|
||||
latitude double precision,
|
||||
stream_type character varying(50),
|
||||
media_server_id character varying(50),
|
||||
create_time character varying(50),
|
||||
constraint uk_gb_stream_unique_gb_id unique (gb_id),
|
||||
constraint uk_gb_stream_unique_app_stream unique (app, stream)
|
||||
);
|
||||
|
||||
create table wvp_log (
|
||||
id serial primary key ,
|
||||
name character varying(50),
|
||||
type character varying(50),
|
||||
uri character varying(200),
|
||||
address character varying(50),
|
||||
result character varying(50),
|
||||
timing bigint,
|
||||
username character varying(50),
|
||||
create_time character varying(50)
|
||||
);
|
||||
|
||||
create table wvp_media_server (
|
||||
id character varying(255) primary key ,
|
||||
ip character varying(50),
|
||||
hook_ip character varying(50),
|
||||
sdp_ip character varying(50),
|
||||
stream_ip character varying(50),
|
||||
http_port integer,
|
||||
http_ssl_port integer,
|
||||
rtmp_port integer,
|
||||
rtmp_ssl_port integer,
|
||||
rtp_proxy_port integer,
|
||||
rtsp_port integer,
|
||||
rtsp_ssl_port integer,
|
||||
auto_config bool default false,
|
||||
secret character varying(50),
|
||||
rtp_enable bool default false,
|
||||
rtp_port_range character varying(50),
|
||||
send_rtp_port_range character varying(50),
|
||||
record_assist_port integer,
|
||||
default_server bool default false,
|
||||
create_time character varying(50),
|
||||
update_time character varying(50),
|
||||
hook_alive_interval integer,
|
||||
record_path character varying(255),
|
||||
record_day integer default 7,
|
||||
constraint uk_media_server_unique_ip_http_port unique (ip, http_port)
|
||||
);
|
||||
|
||||
create table wvp_platform (
|
||||
id serial primary key ,
|
||||
enable bool default false,
|
||||
name character varying(255),
|
||||
server_gb_id character varying(50),
|
||||
server_gb_domain character varying(50),
|
||||
server_ip character varying(50),
|
||||
server_port integer,
|
||||
device_gb_id character varying(50),
|
||||
device_ip character varying(50),
|
||||
device_port character varying(50),
|
||||
username character varying(255),
|
||||
password character varying(50),
|
||||
expires character varying(50),
|
||||
keep_timeout character varying(50),
|
||||
transport character varying(50),
|
||||
character_set character varying(50),
|
||||
catalog_id character varying(50),
|
||||
ptz bool default false,
|
||||
rtcp bool default false,
|
||||
status bool default false,
|
||||
start_offline_push bool default false,
|
||||
administrative_division character varying(50),
|
||||
catalog_group integer,
|
||||
create_time character varying(50),
|
||||
update_time character varying(50),
|
||||
as_message_channel bool default false,
|
||||
auto_push_channel bool default false,
|
||||
constraint uk_platform_unique_server_gb_id unique (server_gb_id)
|
||||
);
|
||||
|
||||
create table wvp_platform_catalog (
|
||||
id character varying(50),
|
||||
platform_id character varying(50),
|
||||
name character varying(255),
|
||||
parent_id character varying(50),
|
||||
civil_code character varying(50),
|
||||
business_group_id character varying(50),
|
||||
constraint uk_platform_catalog_id_platform_id unique (id, platform_id)
|
||||
);
|
||||
|
||||
create table wvp_platform_gb_channel (
|
||||
id serial primary key ,
|
||||
platform_id character varying(50),
|
||||
catalog_id character varying(50),
|
||||
device_channel_id integer,
|
||||
constraint uk_platform_gb_channel_platform_id_catalog_id_device_channel_id unique (platform_id, catalog_id, device_channel_id)
|
||||
);
|
||||
|
||||
create table wvp_platform_gb_stream (
|
||||
id serial primary key,
|
||||
platform_id character varying(50),
|
||||
catalog_id character varying(50),
|
||||
gb_stream_id integer,
|
||||
constraint uk_platform_gb_stream_platform_id_catalog_id_gb_stream_id unique (platform_id, catalog_id, gb_stream_id)
|
||||
);
|
||||
|
||||
create table wvp_stream_proxy (
|
||||
id serial primary key,
|
||||
type character varying(50),
|
||||
app character varying(255),
|
||||
stream character varying(255),
|
||||
url character varying(255),
|
||||
src_url character varying(255),
|
||||
dst_url character varying(255),
|
||||
timeout_ms integer,
|
||||
ffmpeg_cmd_key character varying(255),
|
||||
rtp_type character varying(50),
|
||||
media_server_id character varying(50),
|
||||
enable_audio bool default false,
|
||||
enable_mp4 bool default false,
|
||||
enable bool default false,
|
||||
status boolean,
|
||||
enable_remove_none_reader bool default false,
|
||||
create_time character varying(50),
|
||||
name character varying(255),
|
||||
update_time character varying(50),
|
||||
stream_key character varying(255),
|
||||
enable_disable_none_reader bool default false,
|
||||
constraint uk_stream_proxy_app_stream unique (app, stream)
|
||||
);
|
||||
|
||||
create table wvp_stream_push (
|
||||
id serial primary key,
|
||||
app character varying(255),
|
||||
stream character varying(255),
|
||||
total_reader_count character varying(50),
|
||||
origin_type integer,
|
||||
origin_type_str character varying(50),
|
||||
create_time character varying(50),
|
||||
alive_second integer,
|
||||
media_server_id character varying(50),
|
||||
push_time character varying(50),
|
||||
status bool default false,
|
||||
update_time character varying(50),
|
||||
push_ing bool default false,
|
||||
self bool default false,
|
||||
constraint uk_stream_push_app_stream unique (app, stream)
|
||||
);
|
||||
create table wvp_cloud_record (
|
||||
id serial primary key,
|
||||
app character varying(255),
|
||||
stream character varying(255),
|
||||
call_id character varying(255),
|
||||
start_time bigint,
|
||||
end_time bigint,
|
||||
media_server_id character varying(50),
|
||||
file_name character varying(255),
|
||||
folder character varying(255),
|
||||
file_path character varying(255),
|
||||
collect bool default false,
|
||||
file_size bigint,
|
||||
time_len bigint,
|
||||
constraint uk_stream_push_app_stream_path unique (app, stream, file_path)
|
||||
);
|
||||
|
||||
create table wvp_user (
|
||||
id serial primary key,
|
||||
username character varying(255),
|
||||
password character varying(255),
|
||||
role_id integer,
|
||||
create_time character varying(50),
|
||||
update_time character varying(50),
|
||||
push_key character varying(50),
|
||||
constraint uk_user_username unique (username)
|
||||
);
|
||||
|
||||
create table wvp_user_role (
|
||||
id serial primary key,
|
||||
name character varying(50),
|
||||
authority character varying(50),
|
||||
create_time character varying(50),
|
||||
update_time character varying(50)
|
||||
);
|
||||
create table wvp_resources_tree (
|
||||
id serial primary key ,
|
||||
is_catalog bool default true,
|
||||
device_channel_id integer ,
|
||||
gb_stream_id integer,
|
||||
name character varying(255),
|
||||
parentId integer,
|
||||
path character varying(255)
|
||||
);
|
||||
|
||||
|
||||
/*初始数据*/
|
||||
INSERT INTO wvp_user VALUES (1, 'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3');
|
||||
INSERT INTO wvp_user_role VALUES (1, 'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57');
|
||||
|
||||
|
||||
|
||||
@ -150,6 +150,8 @@ create table wvp_media_server (
|
||||
create_time character varying(50),
|
||||
update_time character varying(50),
|
||||
hook_alive_interval integer,
|
||||
record_path character varying(255),
|
||||
record_day integer default 7,
|
||||
constraint uk_media_server_unique_ip_http_port unique (ip, http_port)
|
||||
);
|
||||
|
||||
@ -235,6 +237,22 @@ create table wvp_stream_push (
|
||||
common_gb_channel_id integer,
|
||||
constraint uk_stream_push_app_stream unique (app, stream)
|
||||
);
|
||||
create table wvp_cloud_record (
|
||||
id serial primary key,
|
||||
app character varying(255),
|
||||
stream character varying(255),
|
||||
call_id character varying(255),
|
||||
start_time int8,
|
||||
end_time int8,
|
||||
media_server_id character varying(50),
|
||||
file_name character varying(255),
|
||||
folder character varying(255),
|
||||
file_path character varying(255),
|
||||
collect bool default false,
|
||||
file_size int8,
|
||||
time_len int8,
|
||||
constraint uk_stream_push_app_stream_path unique (app, stream, file_path)
|
||||
);
|
||||
|
||||
create table wvp_user (
|
||||
id serial primary key,
|
||||
500
数据库/更新-mysql-2.6.9.sql
Normal file
500
数据库/更新-mysql-2.6.9.sql
Normal file
@ -0,0 +1,500 @@
|
||||
|
||||
alter table device
|
||||
change deviceId device_id varchar(50) not null;
|
||||
|
||||
alter table device
|
||||
change streamMode stream_mode varchar(50) null;
|
||||
|
||||
alter table device
|
||||
change registerTime register_time varchar(50) null;
|
||||
|
||||
alter table device
|
||||
change keepaliveTime keepalive_time varchar(50) null;
|
||||
|
||||
alter table device
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table device
|
||||
change updateTime update_time varchar(50) not null;
|
||||
|
||||
alter table device
|
||||
change subscribeCycleForCatalog subscribe_cycle_for_catalog bool default false;
|
||||
|
||||
alter table device
|
||||
change subscribeCycleForMobilePosition subscribe_cycle_for_mobile_position bool default false;
|
||||
|
||||
alter table device
|
||||
change mobilePositionSubmissionInterval mobile_position_submission_interval int default 5 not null;
|
||||
|
||||
alter table device
|
||||
change subscribeCycleForAlarm subscribe_cycle_for_alarm bool default false;
|
||||
|
||||
alter table device
|
||||
change hostAddress host_address varchar(50) null;
|
||||
|
||||
alter table device
|
||||
change ssrcCheck ssrc_check bool default false;
|
||||
|
||||
alter table device
|
||||
change geoCoordSys geo_coord_sys varchar(50) not null;
|
||||
|
||||
alter table device
|
||||
drop column treeType;
|
||||
|
||||
alter table device
|
||||
change mediaServerId media_server_id varchar(50) default 'auto' null;
|
||||
|
||||
alter table device
|
||||
change sdpIp sdp_ip varchar(50) null;
|
||||
|
||||
alter table device
|
||||
change localIp local_ip varchar(50) null;
|
||||
|
||||
alter table device
|
||||
change asMessageChannel as_message_channel bool default false;
|
||||
|
||||
alter table device
|
||||
change keepaliveIntervalTime keepalive_interval_time int null;
|
||||
|
||||
alter table device
|
||||
change online on_line varchar(50) null;
|
||||
|
||||
alter table device
|
||||
add COLUMN switch_primary_sub_stream bool default false comment '开启主子码流切换的开关(0-不开启,1-开启)现在已知支持设备为 大华、TP——LINK全系设备';
|
||||
|
||||
alter table device_alarm
|
||||
change deviceId device_id varchar(50) not null;
|
||||
|
||||
alter table device_alarm
|
||||
change channelId channel_id varchar(50) not null;
|
||||
|
||||
alter table device_alarm
|
||||
change alarmPriority alarm_priority varchar(50) not null;
|
||||
|
||||
alter table device_alarm
|
||||
change alarmMethod alarm_method varchar(50) null;
|
||||
|
||||
alter table device_alarm
|
||||
change alarmTime alarm_time varchar(50) not null;
|
||||
|
||||
alter table device_alarm
|
||||
change alarmDescription alarm_description varchar(255) null;
|
||||
|
||||
alter table device_alarm
|
||||
change alarmType alarm_type varchar(50) null;
|
||||
|
||||
alter table device_alarm
|
||||
change createTime create_time varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change channelId channel_id varchar(50) not null;
|
||||
|
||||
alter table device_channel
|
||||
change civilCode civil_code varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change parentId parent_id varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change safetyWay safety_way int null;
|
||||
|
||||
alter table device_channel
|
||||
change registerWay register_way int null;
|
||||
|
||||
alter table device_channel
|
||||
change certNum cert_num varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change errCode err_code int null;
|
||||
|
||||
alter table device_channel
|
||||
change endTime end_time varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change ipAddress ip_address varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change PTZType ptz_type int null;
|
||||
|
||||
alter table device_channel
|
||||
change status status bool default false;
|
||||
|
||||
alter table device_channel
|
||||
change streamId stream_id varchar(255) null;
|
||||
|
||||
alter table device_channel
|
||||
change deviceId device_id varchar(50) not null;
|
||||
|
||||
|
||||
alter table device_channel
|
||||
change hasAudio has_audio bool default false;
|
||||
|
||||
alter table device_channel
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table device_channel
|
||||
change updateTime update_time varchar(50) not null;
|
||||
|
||||
alter table device_channel
|
||||
change subCount sub_count int default 0 null;
|
||||
|
||||
alter table device_channel
|
||||
change longitudeGcj02 longitude_gcj02 double null;
|
||||
|
||||
alter table device_channel
|
||||
change latitudeGcj02 latitude_gcj02 double null;
|
||||
|
||||
alter table device_channel
|
||||
change longitudeWgs84 longitude_wgs84 double null;
|
||||
|
||||
alter table device_channel
|
||||
change latitudeWgs84 latitude_wgs84 double null;
|
||||
|
||||
alter table device_channel
|
||||
change businessGroupId business_group_id varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change gpsTime gps_time varchar(50) null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change deviceId device_id varchar(50) not null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change channelId channel_id varchar(50) not null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change deviceName device_name varchar(255) null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change reportSource report_source varchar(50) null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change longitudeGcj02 longitude_gcj02 double null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change latitudeGcj02 latitude_gcj02 double null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change longitudeWgs84 longitude_wgs84 double null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change latitudeWgs84 latitude_wgs84 double null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change createTime create_time varchar(50) null;
|
||||
|
||||
alter table gb_stream
|
||||
change gbStreamId gb_stream_id int auto_increment;
|
||||
|
||||
alter table gb_stream
|
||||
change gbId gb_id varchar(50) not null;
|
||||
|
||||
alter table gb_stream
|
||||
change streamType stream_type varchar(50) null;
|
||||
|
||||
alter table gb_stream
|
||||
change mediaServerId media_server_id varchar(50) null;
|
||||
|
||||
alter table gb_stream
|
||||
change createTime create_time varchar(50) null;
|
||||
|
||||
alter table log
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
change hookIp hook_ip varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
add column send_rtp_port_range varchar(50) default null;
|
||||
|
||||
alter table media_server
|
||||
change sdpIp sdp_ip varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
change streamIp stream_ip varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
change httpPort http_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change httpSSlPort http_ssl_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change rtmpPort rtmp_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change rtmpSSlPort rtmp_ssl_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change rtpProxyPort rtp_proxy_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change rtspPort rtsp_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change rtspSSLPort rtsp_ssl_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change autoConfig auto_config bool default true;
|
||||
|
||||
alter table media_server
|
||||
change rtpEnable rtp_enable bool default false;
|
||||
|
||||
alter table media_server
|
||||
change rtpPortRange rtp_port_range varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
change recordAssistPort record_assist_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change defaultServer default_server bool default false;
|
||||
|
||||
alter table media_server
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
change updateTime update_time varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
change hookAliveInterval hook_alive_interval int not null;
|
||||
|
||||
alter table parent_platform
|
||||
change serverGBId server_gb_id varchar(50) not null;
|
||||
|
||||
alter table parent_platform
|
||||
change serverGBDomain server_gb_domain varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change serverIP server_ip varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change serverPort server_port int null;
|
||||
|
||||
alter table parent_platform
|
||||
change deviceGBId device_gb_id varchar(50) not null;
|
||||
|
||||
alter table parent_platform
|
||||
change deviceIp device_ip varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change devicePort device_port varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change keepTimeout keep_timeout varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change characterSet character_set varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change catalogId catalog_id varchar(50) not null;
|
||||
|
||||
alter table parent_platform
|
||||
change startOfflinePush start_offline_push bool default false;
|
||||
|
||||
alter table parent_platform
|
||||
change administrativeDivision administrative_division varchar(50) not null;
|
||||
|
||||
alter table parent_platform
|
||||
change catalogGroup catalog_group int default 1 null;
|
||||
|
||||
alter table parent_platform
|
||||
change createTime create_time varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change updateTime update_time varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
drop column treeType;
|
||||
|
||||
alter table parent_platform
|
||||
change asMessageChannel as_message_channel bool default false;
|
||||
|
||||
alter table parent_platform
|
||||
change enable enable bool default false;
|
||||
|
||||
alter table parent_platform
|
||||
change ptz ptz bool default false;
|
||||
|
||||
alter table parent_platform
|
||||
change rtcp rtcp bool default false;
|
||||
|
||||
alter table parent_platform
|
||||
change status status bool default false;
|
||||
|
||||
alter table parent_platform
|
||||
change status status bool default false;
|
||||
|
||||
alter table platform_catalog
|
||||
change platformId platform_id varchar(50) not null;
|
||||
|
||||
alter table platform_catalog
|
||||
change parentId parent_id varchar(50) null;
|
||||
|
||||
alter table platform_catalog
|
||||
change civilCode civil_code varchar(50) null;
|
||||
|
||||
alter table platform_catalog
|
||||
change businessGroupId business_group_id varchar(50) null;
|
||||
|
||||
alter table platform_gb_channel
|
||||
change platformId platform_id varchar(50) not null;
|
||||
|
||||
alter table platform_gb_channel
|
||||
change catalogId catalog_id varchar(50) not null;
|
||||
|
||||
alter table platform_gb_channel
|
||||
change deviceChannelId device_channel_id int not null;
|
||||
|
||||
alter table platform_gb_stream
|
||||
change platformId platform_id varchar(50) not null;
|
||||
|
||||
alter table platform_gb_stream
|
||||
change catalogId catalog_id varchar(50) not null;
|
||||
|
||||
alter table platform_gb_stream
|
||||
change gbStreamId gb_stream_id int not null;
|
||||
|
||||
alter table stream_proxy
|
||||
change mediaServerId media_server_id varchar(50) null;
|
||||
|
||||
alter table stream_proxy
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table stream_proxy
|
||||
change updateTime update_time varchar(50) null;
|
||||
|
||||
alter table stream_proxy
|
||||
change enable_remove_none_reader enable_remove_none_reader bool default false;
|
||||
|
||||
alter table stream_proxy
|
||||
change enable_disable_none_reader enable_disable_none_reader bool default false;
|
||||
|
||||
alter table stream_proxy
|
||||
change enable_audio enable_audio bool default false;
|
||||
|
||||
alter table stream_proxy
|
||||
change enable_mp4 enable_mp4 bool default false;
|
||||
|
||||
alter table stream_proxy
|
||||
change enable enable bool default false;
|
||||
|
||||
alter table stream_push
|
||||
change totalReaderCount total_reader_count varchar(50) null;
|
||||
|
||||
alter table stream_push
|
||||
change originType origin_type int null;
|
||||
|
||||
alter table stream_push
|
||||
change originTypeStr origin_type_str varchar(50) null;
|
||||
|
||||
alter table stream_push
|
||||
change createTime create_time varchar(50) null;
|
||||
|
||||
alter table stream_push
|
||||
change aliveSecond alive_second int null;
|
||||
|
||||
alter table stream_push
|
||||
change mediaServerId media_server_id varchar(50) null;
|
||||
|
||||
alter table stream_push
|
||||
change status status bool default false;
|
||||
|
||||
alter table stream_push
|
||||
change pushTime push_time varchar(50) null;
|
||||
|
||||
alter table stream_push
|
||||
change updateTime update_time varchar(50) null;
|
||||
|
||||
alter table stream_push
|
||||
change pushIng push_ing bool default false;
|
||||
|
||||
alter table stream_push
|
||||
change status status bool default false;
|
||||
|
||||
alter table stream_push
|
||||
change self self bool default false;
|
||||
|
||||
alter table stream_push
|
||||
drop column serverId;
|
||||
|
||||
|
||||
alter table user
|
||||
change roleId role_id int not null;
|
||||
|
||||
alter table user
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table user
|
||||
change updateTime update_time varchar(50) not null;
|
||||
|
||||
alter table user
|
||||
change pushKey push_key varchar(50) null;
|
||||
|
||||
alter table user_role
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table user_role
|
||||
change updateTime update_time varchar(50) not null;
|
||||
|
||||
rename table device to wvp_device;
|
||||
rename table device_alarm to wvp_device_alarm;
|
||||
rename table device_channel to wvp_device_channel;
|
||||
rename table device_mobile_position to wvp_device_mobile_position;
|
||||
rename table gb_stream to wvp_gb_stream;
|
||||
rename table log to wvp_log;
|
||||
rename table media_server to wvp_media_server;
|
||||
rename table parent_platform to wvp_platform;
|
||||
rename table platform_catalog to wvp_platform_catalog;
|
||||
rename table platform_gb_channel to wvp_platform_gb_channel;
|
||||
rename table platform_gb_stream to wvp_platform_gb_stream;
|
||||
rename table stream_proxy to wvp_stream_proxy;
|
||||
rename table stream_push to wvp_stream_push;
|
||||
rename table user to wvp_user;
|
||||
rename table user_role to wvp_user_role;
|
||||
|
||||
alter table wvp_device add column broadcast_push_after_ack bool default false;
|
||||
alter table wvp_device_channel add column custom_name varchar(255) null ;
|
||||
alter table wvp_device_channel add column custom_longitude double null ;
|
||||
alter table wvp_device_channel add column custom_latitude double null ;
|
||||
alter table wvp_device_channel add column custom_ptz_type int null ;
|
||||
|
||||
create table wvp_resources_tree (
|
||||
id serial primary key ,
|
||||
is_catalog bool default true,
|
||||
device_channel_id integer ,
|
||||
gb_stream_id integer,
|
||||
name character varying(255),
|
||||
parentId integer,
|
||||
path character varying(255)
|
||||
);
|
||||
|
||||
alter table wvp_platform
|
||||
add auto_push_channel bool default false;
|
||||
|
||||
alter table wvp_stream_proxy
|
||||
add stream_key character varying(255);
|
||||
|
||||
create table wvp_cloud_record (
|
||||
id serial primary key,
|
||||
app character varying(255),
|
||||
stream character varying(255),
|
||||
call_id character varying(255),
|
||||
start_time bigint,
|
||||
end_time bigint,
|
||||
media_server_id character varying(50),
|
||||
file_name character varying(255),
|
||||
folder character varying(255),
|
||||
file_path character varying(255),
|
||||
collect bool default false,
|
||||
file_size bigint,
|
||||
time_len bigint,
|
||||
constraint uk_stream_push_app_stream_path unique (app, stream, file_path)
|
||||
);
|
||||
|
||||
alter table wvp_media_server
|
||||
add record_path character varying(255);
|
||||
|
||||
alter table wvp_media_server
|
||||
add record_day integer default 7;
|
||||
|
||||
|
||||
502
数据库/更新-postgresql-kingbase-2.6.9.sql
Normal file
502
数据库/更新-postgresql-kingbase-2.6.9.sql
Normal file
@ -0,0 +1,502 @@
|
||||
|
||||
alter table device
|
||||
change deviceId device_id varchar(50) not null;
|
||||
|
||||
alter table device
|
||||
change streamMode stream_mode varchar(50) null;
|
||||
|
||||
alter table device
|
||||
change registerTime register_time varchar(50) null;
|
||||
|
||||
alter table device
|
||||
change keepaliveTime keepalive_time varchar(50) null;
|
||||
|
||||
alter table device
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table device
|
||||
change updateTime update_time varchar(50) not null;
|
||||
|
||||
alter table device
|
||||
change subscribeCycleForCatalog subscribe_cycle_for_catalog bool default false;
|
||||
|
||||
alter table device
|
||||
change subscribeCycleForMobilePosition subscribe_cycle_for_mobile_position bool default false;
|
||||
|
||||
alter table device
|
||||
change mobilePositionSubmissionInterval mobile_position_submission_interval int default 5 not null;
|
||||
|
||||
alter table device
|
||||
change subscribeCycleForAlarm subscribe_cycle_for_alarm bool default false;
|
||||
|
||||
alter table device
|
||||
change hostAddress host_address varchar(50) null;
|
||||
|
||||
alter table device
|
||||
change ssrcCheck ssrc_check bool default false;
|
||||
|
||||
alter table device
|
||||
change geoCoordSys geo_coord_sys varchar(50) not null;
|
||||
|
||||
alter table device
|
||||
drop column treeType;
|
||||
|
||||
alter table device
|
||||
change mediaServerId media_server_id varchar(50) default 'auto' null;
|
||||
|
||||
alter table device
|
||||
change sdpIp sdp_ip varchar(50) null;
|
||||
|
||||
alter table device
|
||||
change localIp local_ip varchar(50) null;
|
||||
|
||||
alter table device
|
||||
change asMessageChannel as_message_channel bool default false;
|
||||
|
||||
alter table device
|
||||
change keepaliveIntervalTime keepalive_interval_time int null;
|
||||
|
||||
alter table device
|
||||
change online on_line varchar(50) null;
|
||||
|
||||
alter table device
|
||||
add COLUMN switch_primary_sub_stream bool default false comment '开启主子码流切换的开关(0-不开启,1-开启)现在已知支持设备为 大华、TP——LINK全系设备'
|
||||
|
||||
|
||||
alter table device_alarm
|
||||
change deviceId device_id varchar(50) not null;
|
||||
|
||||
alter table device_alarm
|
||||
change channelId channel_id varchar(50) not null;
|
||||
|
||||
alter table device_alarm
|
||||
change alarmPriority alarm_priority varchar(50) not null;
|
||||
|
||||
alter table device_alarm
|
||||
change alarmMethod alarm_method varchar(50) null;
|
||||
|
||||
alter table device_alarm
|
||||
change alarmTime alarm_time varchar(50) not null;
|
||||
|
||||
alter table device_alarm
|
||||
change alarmDescription alarm_description varchar(255) null;
|
||||
|
||||
alter table device_alarm
|
||||
change alarmType alarm_type varchar(50) null;
|
||||
|
||||
alter table device_alarm
|
||||
change createTime create_time varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change channelId channel_id varchar(50) not null;
|
||||
|
||||
alter table device_channel
|
||||
change civilCode civil_code varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change parentId parent_id varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change safetyWay safety_way int null;
|
||||
|
||||
alter table device_channel
|
||||
change registerWay register_way int null;
|
||||
|
||||
alter table device_channel
|
||||
change certNum cert_num varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change errCode err_code int null;
|
||||
|
||||
alter table device_channel
|
||||
change endTime end_time varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change ipAddress ip_address varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change PTZType ptz_type int null;
|
||||
|
||||
alter table device_channel
|
||||
change status status bool default false;
|
||||
|
||||
alter table device_channel
|
||||
change streamId stream_id varchar(255) null;
|
||||
|
||||
alter table device_channel
|
||||
change deviceId device_id varchar(50) not null;
|
||||
|
||||
|
||||
alter table device_channel
|
||||
change hasAudio has_audio bool default false;
|
||||
|
||||
alter table device_channel
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table device_channel
|
||||
change updateTime update_time varchar(50) not null;
|
||||
|
||||
alter table device_channel
|
||||
change subCount sub_count int default 0 null;
|
||||
|
||||
alter table device_channel
|
||||
change longitudeGcj02 longitude_gcj02 double null;
|
||||
|
||||
alter table device_channel
|
||||
change latitudeGcj02 latitude_gcj02 double null;
|
||||
|
||||
alter table device_channel
|
||||
change longitudeWgs84 longitude_wgs84 double null;
|
||||
|
||||
alter table device_channel
|
||||
change latitudeWgs84 latitude_wgs84 double null;
|
||||
|
||||
alter table device_channel
|
||||
change businessGroupId business_group_id varchar(50) null;
|
||||
|
||||
alter table device_channel
|
||||
change gpsTime gps_time varchar(50) null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change deviceId device_id varchar(50) not null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change channelId channel_id varchar(50) not null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change deviceName device_name varchar(255) null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change reportSource report_source varchar(50) null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change longitudeGcj02 longitude_gcj02 double null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change latitudeGcj02 latitude_gcj02 double null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change longitudeWgs84 longitude_wgs84 double null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change latitudeWgs84 latitude_wgs84 double null;
|
||||
|
||||
alter table device_mobile_position
|
||||
change createTime create_time varchar(50) null;
|
||||
|
||||
alter table gb_stream
|
||||
change gbStreamId gb_stream_id int auto_increment;
|
||||
|
||||
alter table gb_stream
|
||||
change gbId gb_id varchar(50) not null;
|
||||
|
||||
alter table gb_stream
|
||||
change streamType stream_type varchar(50) null;
|
||||
|
||||
alter table gb_stream
|
||||
change mediaServerId media_server_id varchar(50) null;
|
||||
|
||||
alter table gb_stream
|
||||
change createTime create_time varchar(50) null;
|
||||
|
||||
alter table log
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
change hookIp hook_ip varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
add column send_rtp_port_range varchar(50) default null;
|
||||
|
||||
alter table media_server
|
||||
change sdpIp sdp_ip varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
change streamIp stream_ip varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
change httpPort http_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change httpSSlPort http_ssl_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change rtmpPort rtmp_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change rtmpSSlPort rtmp_ssl_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change rtpProxyPort rtp_proxy_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change rtspPort rtsp_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change rtspSSLPort rtsp_ssl_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change autoConfig auto_config bool default true;
|
||||
|
||||
alter table media_server
|
||||
change rtpEnable rtp_enable bool default false;
|
||||
|
||||
alter table media_server
|
||||
change rtpPortRange rtp_port_range varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
change recordAssistPort record_assist_port int not null;
|
||||
|
||||
alter table media_server
|
||||
change defaultServer default_server bool default false;
|
||||
|
||||
alter table media_server
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
change updateTime update_time varchar(50) not null;
|
||||
|
||||
alter table media_server
|
||||
change hookAliveInterval hook_alive_interval int not null;
|
||||
|
||||
alter table parent_platform
|
||||
change serverGBId server_gb_id varchar(50) not null;
|
||||
|
||||
alter table parent_platform
|
||||
change serverGBDomain server_gb_domain varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change serverIP server_ip varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change serverPort server_port int null;
|
||||
|
||||
alter table parent_platform
|
||||
change deviceGBId device_gb_id varchar(50) not null;
|
||||
|
||||
alter table parent_platform
|
||||
change deviceIp device_ip varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change devicePort device_port varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change keepTimeout keep_timeout varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change characterSet character_set varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change catalogId catalog_id varchar(50) not null;
|
||||
|
||||
alter table parent_platform
|
||||
change startOfflinePush start_offline_push bool default false;
|
||||
|
||||
alter table parent_platform
|
||||
change administrativeDivision administrative_division varchar(50) not null;
|
||||
|
||||
alter table parent_platform
|
||||
change catalogGroup catalog_group int default 1 null;
|
||||
|
||||
alter table parent_platform
|
||||
change createTime create_time varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
change updateTime update_time varchar(50) null;
|
||||
|
||||
alter table parent_platform
|
||||
drop column treeType;
|
||||
|
||||
alter table parent_platform
|
||||
change asMessageChannel as_message_channel bool default false;
|
||||
|
||||
alter table parent_platform
|
||||
change enable enable bool default false;
|
||||
|
||||
alter table parent_platform
|
||||
change ptz ptz bool default false;
|
||||
|
||||
alter table parent_platform
|
||||
change rtcp rtcp bool default false;
|
||||
|
||||
alter table parent_platform
|
||||
change status status bool default false;
|
||||
|
||||
alter table parent_platform
|
||||
change status status bool default false;
|
||||
|
||||
alter table platform_catalog
|
||||
change platformId platform_id varchar(50) not null;
|
||||
|
||||
alter table platform_catalog
|
||||
change parentId parent_id varchar(50) null;
|
||||
|
||||
alter table platform_catalog
|
||||
change civilCode civil_code varchar(50) null;
|
||||
|
||||
alter table platform_catalog
|
||||
change businessGroupId business_group_id varchar(50) null;
|
||||
|
||||
alter table platform_gb_channel
|
||||
change platformId platform_id varchar(50) not null;
|
||||
|
||||
alter table platform_gb_channel
|
||||
change catalogId catalog_id varchar(50) not null;
|
||||
|
||||
alter table platform_gb_channel
|
||||
change deviceChannelId device_channel_id int not null;
|
||||
|
||||
alter table platform_gb_stream
|
||||
change platformId platform_id varchar(50) not null;
|
||||
|
||||
alter table platform_gb_stream
|
||||
change catalogId catalog_id varchar(50) not null;
|
||||
|
||||
alter table platform_gb_stream
|
||||
change gbStreamId gb_stream_id int not null;
|
||||
|
||||
alter table stream_proxy
|
||||
change mediaServerId media_server_id varchar(50) null;
|
||||
|
||||
alter table stream_proxy
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table stream_proxy
|
||||
change updateTime update_time varchar(50) null;
|
||||
|
||||
alter table stream_proxy
|
||||
change enable_remove_none_reader enable_remove_none_reader bool default false;
|
||||
|
||||
alter table stream_proxy
|
||||
change enable_disable_none_reader enable_disable_none_reader bool default false;
|
||||
|
||||
alter table stream_proxy
|
||||
change enable_audio enable_audio bool default false;
|
||||
|
||||
alter table stream_proxy
|
||||
change enable_mp4 enable_mp4 bool default false;
|
||||
|
||||
alter table stream_proxy
|
||||
change enable enable bool default false;
|
||||
|
||||
alter table stream_push
|
||||
change totalReaderCount total_reader_count varchar(50) null;
|
||||
|
||||
alter table stream_push
|
||||
change originType origin_type int null;
|
||||
|
||||
alter table stream_push
|
||||
change originTypeStr origin_type_str varchar(50) null;
|
||||
|
||||
alter table stream_push
|
||||
change createTime create_time varchar(50) null;
|
||||
|
||||
alter table stream_push
|
||||
change aliveSecond alive_second int null;
|
||||
|
||||
alter table stream_push
|
||||
change mediaServerId media_server_id varchar(50) null;
|
||||
|
||||
alter table stream_push
|
||||
change status status bool default false;
|
||||
|
||||
alter table stream_push
|
||||
change pushTime push_time varchar(50) null;
|
||||
|
||||
alter table stream_push
|
||||
change updateTime update_time varchar(50) null;
|
||||
|
||||
alter table stream_push
|
||||
change pushIng push_ing bool default false;
|
||||
|
||||
alter table stream_push
|
||||
change status status bool default false;
|
||||
|
||||
alter table stream_push
|
||||
change self self bool default false;
|
||||
|
||||
alter table stream_push
|
||||
drop column serverId;
|
||||
|
||||
|
||||
alter table user
|
||||
change roleId role_id int not null;
|
||||
|
||||
alter table user
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table user
|
||||
change updateTime update_time varchar(50) not null;
|
||||
|
||||
alter table user
|
||||
change pushKey push_key varchar(50) null;
|
||||
|
||||
alter table user_role
|
||||
change createTime create_time varchar(50) not null;
|
||||
|
||||
alter table user_role
|
||||
change updateTime update_time varchar(50) not null;
|
||||
|
||||
rename table device to wvp_device;
|
||||
rename table device_alarm to wvp_device_alarm;
|
||||
rename table device_channel to wvp_device_channel;
|
||||
rename table device_mobile_position to wvp_device_mobile_position;
|
||||
rename table gb_stream to wvp_gb_stream;
|
||||
rename table log to wvp_log;
|
||||
rename table media_server to wvp_media_server;
|
||||
rename table parent_platform to wvp_platform;
|
||||
rename table platform_catalog to wvp_platform_catalog;
|
||||
rename table platform_gb_channel to wvp_platform_gb_channel;
|
||||
rename table platform_gb_stream to wvp_platform_gb_stream;
|
||||
rename table stream_proxy to wvp_stream_proxy;
|
||||
rename table stream_push to wvp_stream_push;
|
||||
rename table user to wvp_user;
|
||||
rename table user_role to wvp_user_role;
|
||||
|
||||
alter table wvp_device add column broadcast_push_after_ack bool default false;
|
||||
alter table wvp_device_channel add column custom_name varchar(255) null ;
|
||||
alter table wvp_device_channel add column custom_longitude double null ;
|
||||
alter table wvp_device_channel add column custom_latitude double null ;
|
||||
alter table wvp_device_channel add column custom_ptz_type int null ;
|
||||
|
||||
create table wvp_resources_tree (
|
||||
id serial primary key ,
|
||||
is_catalog bool default true,
|
||||
device_channel_id integer ,
|
||||
gb_stream_id integer,
|
||||
name character varying(255),
|
||||
parentId integer,
|
||||
path character varying(255)
|
||||
);
|
||||
|
||||
alter table wvp_platform
|
||||
add auto_push_channel bool default false;
|
||||
|
||||
alter table wvp_stream_proxy
|
||||
add stream_key character varying(255);
|
||||
|
||||
create table wvp_cloud_record (
|
||||
id serial primary key,
|
||||
app character varying(255),
|
||||
stream character varying(255),
|
||||
call_id character varying(255),
|
||||
start_time int8,
|
||||
end_time int8,
|
||||
media_server_id character varying(50),
|
||||
file_name character varying(255),
|
||||
folder character varying(255),
|
||||
file_path character varying(255),
|
||||
collect bool default false,
|
||||
file_size int8,
|
||||
time_len int8,
|
||||
constraint uk_stream_push_app_stream_path unique (app, stream, file_path)
|
||||
);
|
||||
|
||||
alter table wvp_media_server
|
||||
add record_path character varying(255);
|
||||
|
||||
alter table wvp_media_server
|
||||
add record_day integer default 7;
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user