优化国标录像下载,添加进度条以及自动合并文件下载,需要结合新版assist服务使用。
parent
e9586687f7
commit
7d9cc96ef5
|
@ -31,6 +31,9 @@ public class StreamInfo {
|
||||||
private String rtc;
|
private String rtc;
|
||||||
private String mediaServerId;
|
private String mediaServerId;
|
||||||
private Object tracks;
|
private Object tracks;
|
||||||
|
private String startTime;
|
||||||
|
private String endTime;
|
||||||
|
private double progress;
|
||||||
|
|
||||||
public static class TransactionInfo{
|
public static class TransactionInfo{
|
||||||
public String callId;
|
public String callId;
|
||||||
|
@ -264,4 +267,29 @@ public class StreamInfo {
|
||||||
public void setHttps_ts(String https_ts) {
|
public void setHttps_ts(String https_ts) {
|
||||||
this.https_ts = https_ts;
|
this.https_ts = https_ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getStartTime() {
|
||||||
|
return startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartTime(String startTime) {
|
||||||
|
this.startTime = startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEndTime() {
|
||||||
|
return endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndTime(String endTime) {
|
||||||
|
this.endTime = endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getProgress() {
|
||||||
|
return progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProgress(double progress) {
|
||||||
|
this.progress = progress;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.genersoft.iot.vmp.gb28181.bean;
|
package com.genersoft.iot.vmp.gb28181.bean;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
|
||||||
|
|
||||||
public class SsrcTransaction {
|
public class SsrcTransaction {
|
||||||
|
|
||||||
private String deviceId;
|
private String deviceId;
|
||||||
|
@ -10,6 +12,7 @@ public class SsrcTransaction {
|
||||||
private byte[] dialog;
|
private byte[] dialog;
|
||||||
private String mediaServerId;
|
private String mediaServerId;
|
||||||
private String ssrc;
|
private String ssrc;
|
||||||
|
private VideoStreamSessionManager.SessionType type;
|
||||||
|
|
||||||
public String getDeviceId() {
|
public String getDeviceId() {
|
||||||
return deviceId;
|
return deviceId;
|
||||||
|
@ -74,4 +77,12 @@ public class SsrcTransaction {
|
||||||
public void setSsrc(String ssrc) {
|
public void setSsrc(String ssrc) {
|
||||||
this.ssrc = ssrc;
|
this.ssrc = ssrc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VideoStreamSessionManager.SessionType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(VideoStreamSessionManager.SessionType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,8 +156,6 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> {
|
||||||
List<ParentPlatform> parentPlatforms = parentPlatformMap.get(gbId);
|
List<ParentPlatform> parentPlatforms = parentPlatformMap.get(gbId);
|
||||||
if (parentPlatforms != null && parentPlatforms.size() > 0) {
|
if (parentPlatforms != null && parentPlatforms.size() > 0) {
|
||||||
for (ParentPlatform platform : parentPlatforms) {
|
for (ParentPlatform platform : parentPlatforms) {
|
||||||
// String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetup.getServerId() + "_Catalog_" + platform.getServerGBId();
|
|
||||||
// SubscribeInfo subscribeInfo = redisCatchStorage.getSubscribe(key);
|
|
||||||
SubscribeInfo subscribeInfo = subscribeHolder.getCatalogSubscribe(event.getPlatformId());
|
SubscribeInfo subscribeInfo = subscribeHolder.getCatalogSubscribe(event.getPlatformId());
|
||||||
if (subscribeInfo == null) continue;
|
if (subscribeInfo == null) continue;
|
||||||
logger.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId);
|
logger.info("[Catalog事件: {}]平台:{},影响通道{}", event.getType(), platform.getServerGBId(), gbId);
|
||||||
|
|
|
@ -30,6 +30,12 @@ public class VideoStreamSessionManager {
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserSetup userSetup;
|
private UserSetup userSetup;
|
||||||
|
|
||||||
|
public enum SessionType {
|
||||||
|
play,
|
||||||
|
playback,
|
||||||
|
download
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加一个点播/回放的事务信息
|
* 添加一个点播/回放的事务信息
|
||||||
* 后续可以通过流Id/callID
|
* 后续可以通过流Id/callID
|
||||||
|
@ -40,7 +46,7 @@ public class VideoStreamSessionManager {
|
||||||
* @param mediaServerId 所使用的流媒体ID
|
* @param mediaServerId 所使用的流媒体ID
|
||||||
* @param transaction 事务
|
* @param transaction 事务
|
||||||
*/
|
*/
|
||||||
public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, ClientTransaction transaction){
|
public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, ClientTransaction transaction, SessionType type){
|
||||||
SsrcTransaction ssrcTransaction = new SsrcTransaction();
|
SsrcTransaction ssrcTransaction = new SsrcTransaction();
|
||||||
ssrcTransaction.setDeviceId(deviceId);
|
ssrcTransaction.setDeviceId(deviceId);
|
||||||
ssrcTransaction.setChannelId(channelId);
|
ssrcTransaction.setChannelId(channelId);
|
||||||
|
@ -50,6 +56,7 @@ public class VideoStreamSessionManager {
|
||||||
ssrcTransaction.setCallId(callId);
|
ssrcTransaction.setCallId(callId);
|
||||||
ssrcTransaction.setSsrc(ssrc);
|
ssrcTransaction.setSsrc(ssrc);
|
||||||
ssrcTransaction.setMediaServerId(mediaServerId);
|
ssrcTransaction.setMediaServerId(mediaServerId);
|
||||||
|
ssrcTransaction.setType(type);
|
||||||
|
|
||||||
redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId()
|
redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetup.getServerId()
|
||||||
+ "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction);
|
+ "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction);
|
||||||
|
|
|
@ -115,7 +115,9 @@ public interface ISIPCommander {
|
||||||
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
* @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
|
||||||
* @param downloadSpeed 下载倍速参数
|
* @param downloadSpeed 下载倍速参数
|
||||||
*/
|
*/
|
||||||
void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, InviteStreamCallback event, SipSubscribe.Event errorEvent);
|
void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
|
||||||
|
String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
|
||||||
|
SipSubscribe.Event errorEvent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 视频流停止
|
* 视频流停止
|
||||||
|
|
|
@ -428,7 +428,7 @@ public class SIPCommander implements ISIPCommander {
|
||||||
errorEvent.response(e);
|
errorEvent.response(e);
|
||||||
}), e ->{
|
}), e ->{
|
||||||
// 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
|
// 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值
|
||||||
streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction());
|
streamSession.put(device.getDeviceId(), channelId ,"play", streamId, ssrcInfo.getSsrc(), mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction(), VideoStreamSessionManager.SessionType.play);
|
||||||
streamSession.put(device.getDeviceId(), channelId ,"play", e.dialog);
|
streamSession.put(device.getDeviceId(), channelId ,"play", e.dialog);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -537,7 +537,7 @@ public class SIPCommander implements ISIPCommander {
|
||||||
|
|
||||||
transmitRequest(device, request, errorEvent, okEvent -> {
|
transmitRequest(device, request, errorEvent, okEvent -> {
|
||||||
ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
|
ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
|
||||||
streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction());
|
streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.playback);
|
||||||
streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
|
streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
|
||||||
});
|
});
|
||||||
if (inviteStreamCallback != null) {
|
if (inviteStreamCallback != null) {
|
||||||
|
@ -558,8 +558,9 @@ public class SIPCommander implements ISIPCommander {
|
||||||
* @param downloadSpeed 下载倍速参数
|
* @param downloadSpeed 下载倍速参数
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, InviteStreamCallback event
|
public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
|
||||||
, SipSubscribe.Event errorEvent) {
|
String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
|
||||||
|
SipSubscribe.Event errorEvent) {
|
||||||
try {
|
try {
|
||||||
logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
|
logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
|
||||||
|
|
||||||
|
@ -572,8 +573,6 @@ public class SIPCommander implements ISIPCommander {
|
||||||
content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
|
content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
|
||||||
+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
|
+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String streamMode = device.getStreamMode().toUpperCase();
|
String streamMode = device.getStreamMode().toUpperCase();
|
||||||
|
|
||||||
if (userSetup.isSeniorSdp()) {
|
if (userSetup.isSeniorSdp()) {
|
||||||
|
@ -639,15 +638,20 @@ public class SIPCommander implements ISIPCommander {
|
||||||
logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
|
logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
|
||||||
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
|
||||||
(MediaServerItem mediaServerItemInUse, JSONObject json)->{
|
(MediaServerItem mediaServerItemInUse, JSONObject json)->{
|
||||||
event.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
|
hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
|
||||||
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
|
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
|
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
|
||||||
|
if (inviteStreamCallback != null) {
|
||||||
|
inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
|
||||||
|
}
|
||||||
|
transmitRequest(device, request, errorEvent, okEvent->{
|
||||||
|
ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
|
||||||
|
streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), responseEvent.getClientTransaction(), VideoStreamSessionManager.SessionType.download);
|
||||||
|
streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), okEvent.dialog);
|
||||||
|
});
|
||||||
|
|
||||||
ClientTransaction transaction = transmitRequest(device, request, errorEvent);
|
|
||||||
streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), transaction);
|
|
||||||
streamSession.put(device.getDeviceId(), channelId, callIdHeader.getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), transaction);
|
|
||||||
|
|
||||||
} catch ( SipException | ParseException | InvalidArgumentException e) {
|
} catch ( SipException | ParseException | InvalidArgumentException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
|
@ -104,6 +104,7 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple
|
||||||
DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
|
DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
|
||||||
deviceChannel.setParental(0);
|
deviceChannel.setParental(0);
|
||||||
deviceChannel.setParentId(channelReduce.getCatalogId());
|
deviceChannel.setParentId(channelReduce.getCatalogId());
|
||||||
|
deviceChannel.setCivilCode(parentPlatform.getDeviceGBId().substring(0, 6));
|
||||||
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
|
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
|
||||||
// 防止发送过快
|
// 防止发送过快
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
|
|
|
@ -62,7 +62,12 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
|
||||||
if (NotifyType.equals("121")){
|
if (NotifyType.equals("121")){
|
||||||
logger.info("媒体播放完毕,通知关流");
|
logger.info("媒体播放完毕,通知关流");
|
||||||
String channelId =getText(rootElement, "DeviceID");
|
String channelId =getText(rootElement, "DeviceID");
|
||||||
redisCatchStorage.stopPlayback(device.getDeviceId(), channelId, null, callIdHeader.getCallId());
|
// redisCatchStorage.stopPlayback(device.getDeviceId(), channelId, null, callIdHeader.getCallId());
|
||||||
|
// redisCatchStorage.stopDownload(device.getDeviceId(), channelId, null, callIdHeader.getCallId());
|
||||||
|
StreamInfo streamInfo = redisCatchStorage.queryDownload(device.getDeviceId(), channelId, null, callIdHeader.getCallId());
|
||||||
|
// 设置进度100%
|
||||||
|
streamInfo.setProgress(1);
|
||||||
|
redisCatchStorage.startDownload(streamInfo, callIdHeader.getCallId());
|
||||||
cmder.streamByeCmd(device.getDeviceId(), channelId, null, callIdHeader.getCallId());
|
cmder.streamByeCmd(device.getDeviceId(), channelId, null, callIdHeader.getCallId());
|
||||||
// TODO 如果级联播放,需要给上级发送此通知
|
// TODO 如果级联播放,需要给上级发送此通知
|
||||||
|
|
||||||
|
|
|
@ -107,6 +107,7 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem
|
||||||
DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
|
DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
|
||||||
deviceChannel.setParental(0);
|
deviceChannel.setParental(0);
|
||||||
deviceChannel.setParentId(channelReduce.getCatalogId());
|
deviceChannel.setParentId(channelReduce.getCatalogId());
|
||||||
|
deviceChannel.setCivilCode(parentPlatform.getDeviceGBId().substring(0, 6));
|
||||||
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
|
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
|
||||||
// 防止发送过快
|
// 防止发送过快
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
package com.genersoft.iot.vmp.media.zlm;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||||
|
import okhttp3.*;
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ConnectException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class AssistRESTfulUtils {
|
||||||
|
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(AssistRESTfulUtils.class);
|
||||||
|
|
||||||
|
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 httpClientBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public JSONObject sendGet(MediaServerItem mediaServerItem, String api, Map<String, Object> param, RequestCallback callback) {
|
||||||
|
OkHttpClient client = getClient();
|
||||||
|
|
||||||
|
if (mediaServerItem == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(mediaServerItem.getRecordAssistPort())) {
|
||||||
|
logger.warn("未启用Assist服务");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringBuffer stringBuffer = new StringBuffer();
|
||||||
|
stringBuffer.append(String.format("http://%s:%s/%s", mediaServerItem.getIp(), mediaServerItem.getRecordAssistPort(), api));
|
||||||
|
JSONObject responseJSON = null;
|
||||||
|
|
||||||
|
if (param != null && param.keySet().size() > 0) {
|
||||||
|
stringBuffer.append("?");
|
||||||
|
int index = 1;
|
||||||
|
for (String key : param.keySet()){
|
||||||
|
if (param.get(key) != null) {
|
||||||
|
stringBuffer.append(key + "=" + param.get(key));
|
||||||
|
if (index < param.size()) {
|
||||||
|
stringBuffer.append("&");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String url = stringBuffer.toString();
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.get()
|
||||||
|
.url(url)
|
||||||
|
.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 (ConnectException e) {
|
||||||
|
logger.error(String.format("连接Assist失败: %s, %s", e.getCause().getMessage(), e.getMessage()));
|
||||||
|
logger.info("请检查media配置并确认Assist已启动...");
|
||||||
|
}catch (IOException e) {
|
||||||
|
logger.error(String.format("[ %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("连接Assist失败: %s, %s", e.getCause().getMessage(), e.getMessage()));
|
||||||
|
logger.info("请检查media配置并确认Assist已启动...");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return responseJSON;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -215,7 +215,16 @@ public class ZLMHttpHookListener {
|
||||||
if (deviceChannel != null) {
|
if (deviceChannel != null) {
|
||||||
ret.put("enable_audio", deviceChannel.isHasAudio());
|
ret.put("enable_audio", deviceChannel.isHasAudio());
|
||||||
}
|
}
|
||||||
|
// 如果是录像下载就设置视频间隔十秒
|
||||||
|
if (ssrcTransactionForAll.get(0).getType() == VideoStreamSessionManager.SessionType.download) {
|
||||||
|
ret.put("mp4_max_second", 10);
|
||||||
|
ret.put("enable_mp4", true);
|
||||||
|
ret.put("enable_audio", true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
|
return new ResponseEntity<String>(ret.toString(), HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +333,6 @@ public class ZLMHttpHookListener {
|
||||||
if (mediaInfo != null) {
|
if (mediaInfo != null) {
|
||||||
subscribe.response(mediaInfo, json);
|
subscribe.response(mediaInfo, json);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// 流消失移除redis play
|
// 流消失移除redis play
|
||||||
String app = item.getApp();
|
String app = item.getApp();
|
||||||
|
@ -441,6 +449,7 @@ public class ZLMHttpHookListener {
|
||||||
if ("rtp".equals(app)){
|
if ("rtp".equals(app)){
|
||||||
ret.put("close", true);
|
ret.put("close", true);
|
||||||
StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(streamId);
|
StreamInfo streamInfoForPlayCatch = redisCatchStorage.queryPlayByStreamId(streamId);
|
||||||
|
SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, null, streamId);
|
||||||
if (streamInfoForPlayCatch != null) {
|
if (streamInfoForPlayCatch != null) {
|
||||||
// 如果在给上级推流,也不停止。
|
// 如果在给上级推流,也不停止。
|
||||||
if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) {
|
if (redisCatchStorage.isChannelSendingRTP(streamInfoForPlayCatch.getChannelId())) {
|
||||||
|
|
|
@ -31,6 +31,7 @@ public class ZLMHttpHookSubscribe {
|
||||||
on_server_keepalive
|
on_server_keepalive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
public interface Event{
|
public interface Event{
|
||||||
void response(MediaServerItem mediaServerItem, JSONObject response);
|
void response(MediaServerItem mediaServerItem, JSONObject response);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.genersoft.iot.vmp.service;
|
package com.genersoft.iot.vmp.service;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;
|
import com.genersoft.iot.vmp.gb28181.bean.InviteStreamCallback;
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo;
|
import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo;
|
||||||
|
@ -34,4 +35,9 @@ public interface IPlayService {
|
||||||
DeferredResult<ResponseEntity<String>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
|
DeferredResult<ResponseEntity<String>> playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
|
||||||
|
|
||||||
void zlmServerOffline(String mediaServerId);
|
void zlmServerOffline(String mediaServerId);
|
||||||
|
|
||||||
|
DeferredResult<ResponseEntity<String>> download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
|
||||||
|
DeferredResult<ResponseEntity<String>> download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo,String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack);
|
||||||
|
|
||||||
|
StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ 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.callback.RequestMessage;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
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.transmit.cmd.impl.SIPCommanderFroPlatform;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
|
||||||
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||||
|
@ -28,7 +30,6 @@ import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
|
||||||
import com.genersoft.iot.vmp.service.IMediaService;
|
import com.genersoft.iot.vmp.service.IMediaService;
|
||||||
import com.genersoft.iot.vmp.service.IPlayService;
|
import com.genersoft.iot.vmp.service.IPlayService;
|
||||||
import gov.nist.javax.sip.stack.SIPDialog;
|
import gov.nist.javax.sip.stack.SIPDialog;
|
||||||
import jdk.nashorn.internal.ir.RuntimeNode;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -38,10 +39,8 @@ import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.ResourceUtils;
|
import org.springframework.util.ResourceUtils;
|
||||||
import org.springframework.web.context.request.async.DeferredResult;
|
import org.springframework.web.context.request.async.DeferredResult;
|
||||||
|
|
||||||
import javax.sip.header.CallIdHeader;
|
|
||||||
import javax.sip.header.Header;
|
|
||||||
import javax.sip.message.Request;
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@SuppressWarnings(value = {"rawtypes", "unchecked"})
|
@SuppressWarnings(value = {"rawtypes", "unchecked"})
|
||||||
|
@ -71,6 +70,9 @@ public class PlayServiceImpl implements IPlayService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private ZLMRESTfulUtils zlmresTfulUtils;
|
private ZLMRESTfulUtils zlmresTfulUtils;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AssistRESTfulUtils assistRESTfulUtils;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IMediaService mediaService;
|
private IMediaService mediaService;
|
||||||
|
|
||||||
|
@ -344,7 +346,7 @@ public class PlayServiceImpl implements IPlayService {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId, uuid, result);
|
resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId, uuid, result);
|
||||||
RequestMessage msg = new RequestMessage();
|
RequestMessage msg = new RequestMessage();
|
||||||
msg.setId(uuid);
|
msg.setId(uuid);
|
||||||
msg.setKey(key);
|
msg.setKey(key);
|
||||||
|
@ -405,6 +407,136 @@ public class PlayServiceImpl implements IPlayService {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeferredResult<ResponseEntity<String>> download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) {
|
||||||
|
Device device = storager.queryVideoDevice(deviceId);
|
||||||
|
if (device == null) return null;
|
||||||
|
MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
|
||||||
|
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true);
|
||||||
|
|
||||||
|
return download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed,infoCallBack, hookCallBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeferredResult<ResponseEntity<String>> download(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, InviteStreamCallback infoCallBack, PlayBackCallback hookCallBack) {
|
||||||
|
if (mediaServerItem == null || ssrcInfo == null) return null;
|
||||||
|
String uuid = UUID.randomUUID().toString();
|
||||||
|
String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;
|
||||||
|
DeferredResult<ResponseEntity<String>> result = new DeferredResult<>(30000L);
|
||||||
|
Device device = storager.queryVideoDevice(deviceId);
|
||||||
|
if (device == null) {
|
||||||
|
result.setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
resultHolder.put(key, uuid, result);
|
||||||
|
RequestMessage msg = new RequestMessage();
|
||||||
|
msg.setId(uuid);
|
||||||
|
msg.setKey(key);
|
||||||
|
WVPResult<StreamInfo> wvpResult = new WVPResult<>();
|
||||||
|
msg.setData(wvpResult);
|
||||||
|
PlayBackResult<RequestMessage> downloadResult = new PlayBackResult<>();
|
||||||
|
downloadResult.setData(msg);
|
||||||
|
|
||||||
|
Timer timer = new Timer();
|
||||||
|
timer.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
logger.warn(String.format("录像下载请求超时,deviceId:%s ,channelId:%s", deviceId, channelId));
|
||||||
|
wvpResult.setCode(-1);
|
||||||
|
wvpResult.setMsg("录像下载请求超时");
|
||||||
|
downloadResult.setCode(-1);
|
||||||
|
hookCallBack.call(downloadResult);
|
||||||
|
SIPDialog dialog = streamSession.getDialogByStream(deviceId, channelId, ssrcInfo.getStream());
|
||||||
|
// 点播超时回复BYE 同时释放ssrc以及此次点播的资源
|
||||||
|
if (dialog != null) {
|
||||||
|
// 点播超时回复BYE 同时释放ssrc以及此次点播的资源
|
||||||
|
cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null);
|
||||||
|
}else {
|
||||||
|
mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
|
||||||
|
mediaServerService.closeRTPServer(deviceId, channelId, ssrcInfo.getStream());
|
||||||
|
streamSession.remove(deviceId, channelId, ssrcInfo.getStream());
|
||||||
|
}
|
||||||
|
cmder.streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), null);
|
||||||
|
// 回复之前所有的点播请求
|
||||||
|
hookCallBack.call(downloadResult);
|
||||||
|
}
|
||||||
|
}, userSetup.getPlayTimeout());
|
||||||
|
cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, infoCallBack,
|
||||||
|
inviteStreamInfo -> {
|
||||||
|
logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString());
|
||||||
|
timer.cancel();
|
||||||
|
StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
|
||||||
|
streamInfo.setStartTime(startTime);
|
||||||
|
streamInfo.setEndTime(endTime);
|
||||||
|
if (streamInfo == null) {
|
||||||
|
logger.warn("录像下载API调用失败!");
|
||||||
|
wvpResult.setCode(-1);
|
||||||
|
wvpResult.setMsg("录像下载API调用失败");
|
||||||
|
downloadResult.setCode(-1);
|
||||||
|
hookCallBack.call(downloadResult);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId());
|
||||||
|
wvpResult.setCode(0);
|
||||||
|
wvpResult.setMsg("success");
|
||||||
|
wvpResult.setData(streamInfo);
|
||||||
|
downloadResult.setCode(0);
|
||||||
|
downloadResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());
|
||||||
|
downloadResult.setResponse(inviteStreamInfo.getResponse());
|
||||||
|
hookCallBack.call(downloadResult);
|
||||||
|
}, event -> {
|
||||||
|
timer.cancel();
|
||||||
|
downloadResult.setCode(-1);
|
||||||
|
wvpResult.setCode(-1);
|
||||||
|
wvpResult.setMsg(String.format("录像下载失败, 错误码: %s, %s", event.statusCode, event.msg));
|
||||||
|
downloadResult.setEvent(event);
|
||||||
|
hookCallBack.call(downloadResult);
|
||||||
|
streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream) {
|
||||||
|
StreamInfo streamInfo = redisCatchStorage.queryDownload(deviceId, channelId, stream, null);
|
||||||
|
if (streamInfo != null) {
|
||||||
|
if (streamInfo.getProgress() == 1) {
|
||||||
|
return streamInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前已下载时长
|
||||||
|
String mediaServerId = streamInfo.getMediaServerId();
|
||||||
|
MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
|
||||||
|
if (mediaServerItem == null) {
|
||||||
|
logger.warn("查询录像信息时发现节点已离线");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (mediaServerItem.getRecordAssistPort() != 0) {
|
||||||
|
JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, streamInfo.getApp(), streamInfo.getStream(), null);
|
||||||
|
if (jsonObject != null && jsonObject.getInteger("code") == 0) {
|
||||||
|
long duration = jsonObject.getLong("data");
|
||||||
|
|
||||||
|
if (duration == 0) {
|
||||||
|
streamInfo.setProgress(0);
|
||||||
|
}else {
|
||||||
|
String startTime = streamInfo.getStartTime();
|
||||||
|
String endTime = streamInfo.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, BigDecimal.ROUND_HALF_UP);
|
||||||
|
double process = divide.doubleValue();
|
||||||
|
streamInfo.setProgress(process);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return streamInfo;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String uuid) {
|
public void onPublishHandlerForDownload(InviteStreamInfo inviteStreamInfo, String deviceId, String channelId, String uuid) {
|
||||||
RequestMessage msg = new RequestMessage();
|
RequestMessage msg = new RequestMessage();
|
||||||
|
|
|
@ -91,7 +91,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
|
||||||
MediaServerItem mediaInfo;
|
MediaServerItem mediaInfo;
|
||||||
WVPResult<StreamInfo> wvpResult = new WVPResult<>();
|
WVPResult<StreamInfo> wvpResult = new WVPResult<>();
|
||||||
wvpResult.setCode(0);
|
wvpResult.setCode(0);
|
||||||
if ("auto".equals(param.getMediaServerId())){
|
if (param.getMediaServerId() == null || "auto".equals(param.getMediaServerId())){
|
||||||
mediaInfo = mediaServerService.getMediaServerForMinimumLoad();
|
mediaInfo = mediaServerService.getMediaServerForMinimumLoad();
|
||||||
}else {
|
}else {
|
||||||
mediaInfo = mediaServerService.getOne(param.getMediaServerId());
|
mediaInfo = mediaServerService.getOne(param.getMediaServerId());
|
||||||
|
|
|
@ -169,6 +169,8 @@ public interface IRedisCatchStorage {
|
||||||
|
|
||||||
StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId);
|
StreamInfo queryDownload(String deviceId, String channelId, String stream, String callId);
|
||||||
|
|
||||||
|
boolean stopDownload(String deviceId, String channelId, String stream, String callId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查找第三方系统留下的国标预设值
|
* 查找第三方系统留下的国标预设值
|
||||||
* @param queryKey
|
* @param queryKey
|
||||||
|
|
|
@ -166,8 +166,42 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean startDownload(StreamInfo stream, String callId) {
|
public boolean startDownload(StreamInfo stream, String callId) {
|
||||||
return redis.set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,
|
boolean result;
|
||||||
userSetup.getServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream);
|
if (stream.getProgress() == 1) {
|
||||||
|
result = redis.set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,
|
||||||
|
userSetup.getServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream);
|
||||||
|
}else {
|
||||||
|
result = redis.set(String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,
|
||||||
|
userSetup.getServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream, 60*60);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean stopDownload(String deviceId, String channelId, String stream, String callId) {
|
||||||
|
DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);
|
||||||
|
if (deviceChannel != null) {
|
||||||
|
deviceChannel.setStreamId(null);
|
||||||
|
deviceChannel.setDeviceId(deviceId);
|
||||||
|
deviceChannelMapper.update(deviceChannel);
|
||||||
|
}
|
||||||
|
if (deviceId == null) deviceId = "*";
|
||||||
|
if (channelId == null) channelId = "*";
|
||||||
|
if (stream == null) stream = "*";
|
||||||
|
if (callId == null) callId = "*";
|
||||||
|
String key = String.format("%S_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,
|
||||||
|
userSetup.getServerId(),
|
||||||
|
deviceId,
|
||||||
|
channelId,
|
||||||
|
stream,
|
||||||
|
callId
|
||||||
|
);
|
||||||
|
List<Object> scan = redis.scan(key);
|
||||||
|
if (scan.size() > 0) {
|
||||||
|
for (Object keyObj : scan) {
|
||||||
|
redis.del((String) keyObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,150 +0,0 @@
|
||||||
package com.genersoft.iot.vmp.vmanager.gb28181.playback;
|
|
||||||
|
|
||||||
import com.genersoft.iot.vmp.common.StreamInfo;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
|
|
||||||
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
|
||||||
import com.genersoft.iot.vmp.service.IMediaServerService;
|
|
||||||
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
|
||||||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
|
|
||||||
import com.genersoft.iot.vmp.service.IPlayService;
|
|
||||||
import io.swagger.annotations.Api;
|
|
||||||
import io.swagger.annotations.ApiImplicitParam;
|
|
||||||
import io.swagger.annotations.ApiImplicitParams;
|
|
||||||
import io.swagger.annotations.ApiOperation;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.bean.Device;
|
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
|
|
||||||
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
|
|
||||||
import org.springframework.web.context.request.async.DeferredResult;
|
|
||||||
|
|
||||||
import javax.sip.message.Response;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Api(tags = "历史媒体下载")
|
|
||||||
@CrossOrigin
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/download")
|
|
||||||
public class DownloadController {
|
|
||||||
|
|
||||||
private final static Logger logger = LoggerFactory.getLogger(DownloadController.class);
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private SIPCommander cmder;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IVideoManagerStorager storager;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IRedisCatchStorage redisCatchStorage;
|
|
||||||
|
|
||||||
// @Autowired
|
|
||||||
// private ZLMRESTfulUtils zlmresTfulUtils;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IPlayService playService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private DeferredResultHolder resultHolder;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IMediaServerService mediaServerService;
|
|
||||||
|
|
||||||
@ApiOperation("开始历史媒体下载")
|
|
||||||
@ApiImplicitParams({
|
|
||||||
@ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
|
|
||||||
@ApiImplicitParam(name = "channelId", value = "通道ID", dataTypeClass = String.class),
|
|
||||||
@ApiImplicitParam(name = "startTime", value = "开始时间", dataTypeClass = String.class),
|
|
||||||
@ApiImplicitParam(name = "endTime", value = "结束时间", dataTypeClass = String.class),
|
|
||||||
@ApiImplicitParam(name = "downloadSpeed", value = "下载倍速", dataTypeClass = String.class),
|
|
||||||
})
|
|
||||||
@GetMapping("/start/{deviceId}/{channelId}")
|
|
||||||
public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId, @PathVariable String channelId,
|
|
||||||
String startTime, String endTime, String downloadSpeed) {
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(String.format("历史媒体下载 API调用,deviceId:%s,channelId:%s,downloadSpeed:%s", deviceId, channelId, downloadSpeed));
|
|
||||||
}
|
|
||||||
String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;
|
|
||||||
String uuid = UUID.randomUUID().toString();
|
|
||||||
DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(30000L);
|
|
||||||
// 超时处理
|
|
||||||
result.onTimeout(()->{
|
|
||||||
logger.warn(String.format("设备下载响应超时,deviceId:%s ,channelId:%s", deviceId, channelId));
|
|
||||||
RequestMessage msg = new RequestMessage();
|
|
||||||
msg.setId(uuid);
|
|
||||||
msg.setKey(key);
|
|
||||||
msg.setData("Timeout");
|
|
||||||
resultHolder.invokeAllResult(msg);
|
|
||||||
});
|
|
||||||
if(resultHolder.exist(key, null)) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
resultHolder.put(key, uuid, result);
|
|
||||||
Device device = storager.queryVideoDevice(deviceId);
|
|
||||||
|
|
||||||
MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
|
|
||||||
if (newMediaServerItem == null) {
|
|
||||||
logger.warn(String.format("设备下载响应超时,deviceId:%s ,channelId:%s", deviceId, channelId));
|
|
||||||
RequestMessage msg = new RequestMessage();
|
|
||||||
msg.setId(uuid);
|
|
||||||
msg.setKey(key);
|
|
||||||
msg.setData("Timeout");
|
|
||||||
resultHolder.invokeAllResult(msg);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true);
|
|
||||||
|
|
||||||
cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (InviteStreamInfo inviteStreamInfo) -> {
|
|
||||||
logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString());
|
|
||||||
playService.onPublishHandlerForDownload(inviteStreamInfo, deviceId, channelId, uuid);
|
|
||||||
}, event -> {
|
|
||||||
RequestMessage msg = new RequestMessage();
|
|
||||||
msg.setId(uuid);
|
|
||||||
msg.setKey(key);
|
|
||||||
msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));
|
|
||||||
resultHolder.invokeAllResult(msg);
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiOperation("停止历史媒体下载")
|
|
||||||
@ApiImplicitParams({
|
|
||||||
@ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
|
|
||||||
@ApiImplicitParam(name = "channelId", value = "通道ID", dataTypeClass = String.class),
|
|
||||||
@ApiImplicitParam(name = "stream", value = "流ID", dataTypeClass = String.class),
|
|
||||||
})
|
|
||||||
@GetMapping("/stop/{deviceId}/{channelId}/{stream}")
|
|
||||||
public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) {
|
|
||||||
|
|
||||||
cmder.streamByeCmd(deviceId, channelId, stream, null);
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(String.format("设备历史媒体下载停止 API调用,deviceId/channelId:%s_%s", deviceId, channelId));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deviceId != null && channelId != null) {
|
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
json.put("deviceId", deviceId);
|
|
||||||
json.put("channelId", channelId);
|
|
||||||
return new ResponseEntity<String>(json.toString(), HttpStatus.OK);
|
|
||||||
} else {
|
|
||||||
logger.warn("设备历史媒体下载停止API调用失败!");
|
|
||||||
return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,13 @@
|
||||||
package com.genersoft.iot.vmp.vmanager.gb28181.record;
|
package com.genersoft.iot.vmp.vmanager.gb28181.record;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.genersoft.iot.vmp.common.StreamInfo;
|
||||||
|
import com.genersoft.iot.vmp.gb28181.bean.InviteStreamInfo;
|
||||||
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
|
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
|
||||||
|
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
|
||||||
|
import com.genersoft.iot.vmp.service.IMediaServerService;
|
||||||
|
import com.genersoft.iot.vmp.service.IPlayService;
|
||||||
|
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiImplicitParam;
|
import io.swagger.annotations.ApiImplicitParam;
|
||||||
import io.swagger.annotations.ApiImplicitParams;
|
import io.swagger.annotations.ApiImplicitParams;
|
||||||
|
@ -8,6 +15,7 @@ import io.swagger.annotations.ApiOperation;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
@ -41,6 +49,12 @@ public class GBRecordController {
|
||||||
@Autowired
|
@Autowired
|
||||||
private DeferredResultHolder resultHolder;
|
private DeferredResultHolder resultHolder;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IPlayService playService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMediaServerService mediaServerService;
|
||||||
|
|
||||||
@ApiOperation("录像查询")
|
@ApiOperation("录像查询")
|
||||||
@ApiImplicitParams({
|
@ApiImplicitParams({
|
||||||
@ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
|
@ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
|
||||||
|
@ -77,4 +91,111 @@ public class GBRecordController {
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiOperation("开始历史媒体下载")
|
||||||
|
@ApiImplicitParams({
|
||||||
|
@ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
|
||||||
|
@ApiImplicitParam(name = "channelId", value = "通道ID", dataTypeClass = String.class),
|
||||||
|
@ApiImplicitParam(name = "startTime", value = "开始时间", dataTypeClass = String.class),
|
||||||
|
@ApiImplicitParam(name = "endTime", value = "结束时间", dataTypeClass = String.class),
|
||||||
|
@ApiImplicitParam(name = "downloadSpeed", value = "下载倍速", dataTypeClass = String.class),
|
||||||
|
})
|
||||||
|
@GetMapping("/download/start/{deviceId}/{channelId}")
|
||||||
|
public DeferredResult<ResponseEntity<String>> download(@PathVariable String deviceId, @PathVariable String channelId,
|
||||||
|
String startTime, String endTime, String downloadSpeed) {
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(String.format("历史媒体下载 API调用,deviceId:%s,channelId:%s,downloadSpeed:%s", deviceId, channelId, downloadSpeed));
|
||||||
|
}
|
||||||
|
// String key = DeferredResultHolder.CALLBACK_CMD_DOWNLOAD + deviceId + channelId;
|
||||||
|
// String uuid = UUID.randomUUID().toString();
|
||||||
|
// DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(30000L);
|
||||||
|
// // 超时处理
|
||||||
|
// result.onTimeout(()->{
|
||||||
|
// logger.warn(String.format("设备下载响应超时,deviceId:%s ,channelId:%s", deviceId, channelId));
|
||||||
|
// RequestMessage msg = new RequestMessage();
|
||||||
|
// msg.setId(uuid);
|
||||||
|
// msg.setKey(key);
|
||||||
|
// msg.setData("Timeout");
|
||||||
|
// resultHolder.invokeAllResult(msg);
|
||||||
|
// });
|
||||||
|
// if(resultHolder.exist(key, null)) {
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
// resultHolder.put(key, uuid, result);
|
||||||
|
// Device device = storager.queryVideoDevice(deviceId);
|
||||||
|
//
|
||||||
|
// MediaServerItem newMediaServerItem = playService.getNewMediaServerItem(device);
|
||||||
|
// if (newMediaServerItem == null) {
|
||||||
|
// logger.warn(String.format("设备下载响应超时,deviceId:%s ,channelId:%s", deviceId, channelId));
|
||||||
|
// RequestMessage msg = new RequestMessage();
|
||||||
|
// msg.setId(uuid);
|
||||||
|
// msg.setKey(key);
|
||||||
|
// msg.setData("Timeout");
|
||||||
|
// resultHolder.invokeAllResult(msg);
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true);
|
||||||
|
//
|
||||||
|
// cmder.downloadStreamCmd(newMediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, (InviteStreamInfo inviteStreamInfo) -> {
|
||||||
|
// logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString());
|
||||||
|
// playService.onPublishHandlerForDownload(inviteStreamInfo, deviceId, channelId, uuid);
|
||||||
|
// }, event -> {
|
||||||
|
// RequestMessage msg = new RequestMessage();
|
||||||
|
// msg.setId(uuid);
|
||||||
|
// msg.setKey(key);
|
||||||
|
// msg.setData(String.format("回放失败, 错误码: %s, %s", event.statusCode, event.msg));
|
||||||
|
// resultHolder.invokeAllResult(msg);
|
||||||
|
// });
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(String.format("设备回放 API调用,deviceId:%s ,channelId:%s", deviceId, channelId));
|
||||||
|
}
|
||||||
|
|
||||||
|
DeferredResult<ResponseEntity<String>> result = playService.download(deviceId, channelId, startTime, endTime, Integer.parseInt(downloadSpeed), null, hookCallBack->{
|
||||||
|
resultHolder.invokeResult(hookCallBack.getData());
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("停止历史媒体下载")
|
||||||
|
@ApiImplicitParams({
|
||||||
|
@ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
|
||||||
|
@ApiImplicitParam(name = "channelId", value = "通道ID", dataTypeClass = String.class),
|
||||||
|
@ApiImplicitParam(name = "stream", value = "流ID", dataTypeClass = String.class),
|
||||||
|
})
|
||||||
|
@GetMapping("/download/stop/{deviceId}/{channelId}/{stream}")
|
||||||
|
public ResponseEntity<String> playStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) {
|
||||||
|
|
||||||
|
cmder.streamByeCmd(deviceId, channelId, stream, null);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(String.format("设备历史媒体下载停止 API调用,deviceId/channelId:%s_%s", deviceId, channelId));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deviceId != null && channelId != null) {
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
json.put("deviceId", deviceId);
|
||||||
|
json.put("channelId", channelId);
|
||||||
|
return new ResponseEntity<String>(json.toString(), HttpStatus.OK);
|
||||||
|
} else {
|
||||||
|
logger.warn("设备历史媒体下载停止API调用失败!");
|
||||||
|
return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取历史媒体下载进度")
|
||||||
|
@ApiImplicitParams({
|
||||||
|
@ApiImplicitParam(name = "deviceId", value = "设备ID", dataTypeClass = String.class),
|
||||||
|
@ApiImplicitParam(name = "channelId", value = "通道ID", dataTypeClass = String.class),
|
||||||
|
@ApiImplicitParam(name = "stream", value = "流ID", dataTypeClass = String.class),
|
||||||
|
})
|
||||||
|
@GetMapping("/download/progress/{deviceId}/{channelId}/{stream}")
|
||||||
|
public ResponseEntity<StreamInfo> getProgress(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) {
|
||||||
|
|
||||||
|
StreamInfo streamInfo = playService.getDownLoadInfo(deviceId, channelId, stream);
|
||||||
|
return new ResponseEntity<>(streamInfo, HttpStatus.OK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ const devWebpackConfig = merge(baseWebpackConfig, {
|
||||||
contentBase: false, // since we use CopyWebpackPlugin.
|
contentBase: false, // since we use CopyWebpackPlugin.
|
||||||
compress: true,
|
compress: true,
|
||||||
host: HOST || config.dev.host,
|
host: HOST || config.dev.host,
|
||||||
|
// host:'127.0.0.1',
|
||||||
port: PORT || config.dev.port,
|
port: PORT || config.dev.port,
|
||||||
open: config.dev.autoOpenBrowser,
|
open: config.dev.autoOpenBrowser,
|
||||||
overlay: config.dev.errorOverlay
|
overlay: config.dev.errorOverlay
|
||||||
|
|
|
@ -29,11 +29,13 @@ module.exports = {
|
||||||
},
|
},
|
||||||
|
|
||||||
// Various Dev Server settings
|
// Various Dev Server settings
|
||||||
host: 'localhost', // can be overwritten by process.env.HOST
|
host:"127.0.0.1",
|
||||||
|
useLocalIp: false, // can be overwritten by process.env.HOST
|
||||||
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
|
port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
|
||||||
autoOpenBrowser: false,
|
autoOpenBrowser: false,
|
||||||
errorOverlay: true,
|
errorOverlay: true,
|
||||||
notifyOnErrors: true,
|
notifyOnErrors: true,
|
||||||
|
hot: true,//自动保存
|
||||||
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
|
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
"vue-template-compiler": "^2.5.2",
|
"vue-template-compiler": "^2.5.2",
|
||||||
"webpack": "^3.6.0",
|
"webpack": "^3.6.0",
|
||||||
"webpack-bundle-analyzer": "^2.9.0",
|
"webpack-bundle-analyzer": "^2.9.0",
|
||||||
"webpack-dev-server": "^2.9.1",
|
"webpack-dev-server": "^2.11.5",
|
||||||
"webpack-merge": "^4.1.0"
|
"webpack-merge": "^4.1.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -13382,7 +13382,7 @@
|
||||||
},
|
},
|
||||||
"node_modules/webpack-dev-server": {
|
"node_modules/webpack-dev-server": {
|
||||||
"version": "2.11.5",
|
"version": "2.11.5",
|
||||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.11.5.tgz",
|
"resolved": "https://registry.npmmirror.com/webpack-dev-server/-/webpack-dev-server-2.11.5.tgz",
|
||||||
"integrity": "sha512-7TdOKKt7G3sWEhPKV0zP+nD0c4V9YKUJ3wDdBwQsZNo58oZIRoVIu66pg7PYkBW8A74msP9C2kLwmxGHndz/pw==",
|
"integrity": "sha512-7TdOKKt7G3sWEhPKV0zP+nD0c4V9YKUJ3wDdBwQsZNo58oZIRoVIu66pg7PYkBW8A74msP9C2kLwmxGHndz/pw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -25569,7 +25569,7 @@
|
||||||
},
|
},
|
||||||
"webpack-dev-server": {
|
"webpack-dev-server": {
|
||||||
"version": "2.11.5",
|
"version": "2.11.5",
|
||||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.11.5.tgz",
|
"resolved": "https://registry.npmmirror.com/webpack-dev-server/-/webpack-dev-server-2.11.5.tgz",
|
||||||
"integrity": "sha512-7TdOKKt7G3sWEhPKV0zP+nD0c4V9YKUJ3wDdBwQsZNo58oZIRoVIu66pg7PYkBW8A74msP9C2kLwmxGHndz/pw==",
|
"integrity": "sha512-7TdOKKt7G3sWEhPKV0zP+nD0c4V9YKUJ3wDdBwQsZNo58oZIRoVIu66pg7PYkBW8A74msP9C2kLwmxGHndz/pw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
|
|
@ -175,6 +175,7 @@
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<recordDownload ref="recordDownload"></recordDownload>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -183,15 +184,15 @@
|
||||||
// import LivePlayer from '@liveqing/liveplayer'
|
// import LivePlayer from '@liveqing/liveplayer'
|
||||||
// import player from '../dialog/easyPlayer.vue'
|
// import player from '../dialog/easyPlayer.vue'
|
||||||
import player from '../dialog/jessibuca.vue'
|
import player from '../dialog/jessibuca.vue'
|
||||||
|
import recordDownload from '../dialog/recordDownload.vue'
|
||||||
export default {
|
export default {
|
||||||
name: 'devicePlayer',
|
name: 'devicePlayer',
|
||||||
props: {},
|
props: {},
|
||||||
components: {
|
components: {
|
||||||
player,
|
player,recordDownload,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
getPlayerShared: function () {
|
getPlayerShared: function () {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sharedUrl: window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl),
|
sharedUrl: window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl),
|
||||||
sharedIframe: '<iframe src="' + window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl) + '"></iframe>',
|
sharedIframe: '<iframe src="' + window.location.origin + '/#/play/wasm/' + encodeURIComponent(this.videoUrl) + '"></iframe>',
|
||||||
|
@ -250,7 +251,7 @@ export default {
|
||||||
that.tracks = [];
|
that.tracks = [];
|
||||||
that.tracksLoading = true;
|
that.tracksLoading = true;
|
||||||
that.tracksNotLoaded = false;
|
that.tracksNotLoaded = false;
|
||||||
if (tab.name == "codec") {
|
if (tab.name === "codec") {
|
||||||
this.$axios({
|
this.$axios({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/zlm/' +this.mediaServerId+ '/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId
|
url: '/zlm/' +this.mediaServerId+ '/index/api/getMediaInfo?vhost=__defaultVhost__&schema=rtmp&app='+ this.app +'&stream='+ this.streamId
|
||||||
|
@ -340,7 +341,7 @@ export default {
|
||||||
this.$refs.videoPlayer.pause()
|
this.$refs.videoPlayer.pause()
|
||||||
that.$axios({
|
that.$axios({
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/api/play/convert/' + that.streamId
|
url: '/api/gb_record/convert/' + that.streamId
|
||||||
}).then(function (res) {
|
}).then(function (res) {
|
||||||
if (res.data.code == 0) {
|
if (res.data.code == 0) {
|
||||||
that.convertKey = res.data.key;
|
that.convertKey = res.data.key;
|
||||||
|
@ -474,8 +475,8 @@ export default {
|
||||||
console.log(this.seekTime)
|
console.log(this.seekTime)
|
||||||
if (that.streamId != "") {
|
if (that.streamId != "") {
|
||||||
that.stopPlayRecord(function () {
|
that.stopPlayRecord(function () {
|
||||||
that.streamId = "",
|
that.streamId = "";
|
||||||
that.playRecord(row);
|
that.playRecord(row);
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.$axios({
|
this.$axios({
|
||||||
|
@ -506,22 +507,36 @@ export default {
|
||||||
downloadRecord: function (row) {
|
downloadRecord: function (row) {
|
||||||
let that = this;
|
let that = this;
|
||||||
if (that.streamId != "") {
|
if (that.streamId != "") {
|
||||||
that.stopDownloadRecord(function () {
|
that.stopDownloadRecord(function (res) {
|
||||||
that.streamId = "",
|
if (res.code == 0) {
|
||||||
that.downloadRecord(row);
|
that.streamId = "";
|
||||||
|
that.downloadRecord(row);
|
||||||
|
}else {
|
||||||
|
this.$message({
|
||||||
|
showClose: true,
|
||||||
|
message: res.data.msg,
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.$axios({
|
this.$axios({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/api/download/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + row.startTime + '&endTime=' +
|
url: '/api/gb_record/download/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + row.startTime + '&endTime=' +
|
||||||
row.endTime + '&downloadSpeed=4'
|
row.endTime + '&downloadSpeed=4'
|
||||||
}).then(function (res) {
|
}).then(function (res) {
|
||||||
var streamInfo = res.data;
|
if (res.data.code == 0) {
|
||||||
that.app = streamInfo.app;
|
let streamInfo = res.data.data;
|
||||||
that.streamId = streamInfo.stream;
|
that.recordPlay = false;
|
||||||
that.mediaServerId = streamInfo.mediaServerId;
|
that.$refs.recordDownload.openDialog(that.deviceId, that.channelId, streamInfo.app, streamInfo.stream, streamInfo.mediaServerId);
|
||||||
that.videoUrl = that.getUrlByStreamInfo(streamInfo);
|
}else {
|
||||||
that.recordPlay = true;
|
that.$message({
|
||||||
|
showClose: true,
|
||||||
|
message: res.data.msg,
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -530,9 +545,9 @@ export default {
|
||||||
this.videoUrl = '';
|
this.videoUrl = '';
|
||||||
this.$axios({
|
this.$axios({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/api/download/stop/' + this.deviceId + "/" + this.channelId+ "/" + this.streamId
|
url: '/api/gb_record/download/stop/' + this.deviceId + "/" + this.channelId+ "/" + this.streamId
|
||||||
}).then(function (res) {
|
}).then((res)=> {
|
||||||
if (callback) callback()
|
if (callback) callback(res)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
ptzCamera: function (command) {
|
ptzCamera: function (command) {
|
||||||
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
<template>
|
||||||
|
<div id="recordDownload" >
|
||||||
|
<el-dialog :title="title" v-if="showDialog" width="45rem" :append-to-body="true" :close-on-click-modal="false" :visible.sync="showDialog" :destroy-on-close="true" @close="close()" center>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="18" style="padding-top: 7px;">
|
||||||
|
<el-progress :percentage="percentage"></el-progress>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6" >
|
||||||
|
<!-- <el-dropdown size="mini" title="播放倍速" style="margin-left: 1px;" @command="gbScale">-->
|
||||||
|
<!-- <el-button-group>-->
|
||||||
|
<!-- <el-button size="mini" style="width: 100%">-->
|
||||||
|
<!-- {{scale}}倍速 <i class="el-icon-arrow-down el-icon--right"></i>-->
|
||||||
|
<!-- </el-button>-->
|
||||||
|
<!-- </el-button-group>-->
|
||||||
|
<!-- <el-dropdown-menu slot="dropdown">-->
|
||||||
|
<!-- <el-dropdown-item command="1">1倍速</el-dropdown-item>-->
|
||||||
|
<!-- <el-dropdown-item command="2">2倍速</el-dropdown-item>-->
|
||||||
|
<!-- <el-dropdown-item command="4">4倍速</el-dropdown-item>-->
|
||||||
|
<!-- </el-dropdown-menu>-->
|
||||||
|
<!-- </el-dropdown>-->
|
||||||
|
<el-button icon="el-icon-download" v-if="percentage < 100" size="mini" title="点击下载可将以缓存部分下载到本地" @click="download()">停止缓存并下载</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import moment from "moment";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'recordDownload',
|
||||||
|
created() {
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
title: "四倍速下载中...",
|
||||||
|
deviceId: "",
|
||||||
|
channelId: "",
|
||||||
|
app: "",
|
||||||
|
stream: "",
|
||||||
|
mediaServerId: "",
|
||||||
|
showDialog: false,
|
||||||
|
scale: 1,
|
||||||
|
percentage: 0.00,
|
||||||
|
streamInfo: null,
|
||||||
|
taskId: null,
|
||||||
|
getProgressRun: false,
|
||||||
|
getProgressForFileRun: false,
|
||||||
|
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openDialog: function (deviceId, channelId, app, stream, mediaServerId) {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.channelId = channelId;
|
||||||
|
this.app = app;
|
||||||
|
this.stream = stream;
|
||||||
|
this.mediaServerId = mediaServerId;
|
||||||
|
this.showDialog = true;
|
||||||
|
this.getProgressRun = true;
|
||||||
|
this.percentage = 0.0;
|
||||||
|
this.getProgressTimer()
|
||||||
|
},
|
||||||
|
getProgressTimer(){
|
||||||
|
if (!this.getProgressRun) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.percentage == 100 ) {
|
||||||
|
this.getFileDownload();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTimeout( ()=>{
|
||||||
|
if (!this.showDialog) return;
|
||||||
|
this.getProgress(this.getProgressTimer())
|
||||||
|
}, 5000)
|
||||||
|
},
|
||||||
|
getProgress: function (callback){
|
||||||
|
this.$axios({
|
||||||
|
method: 'get',
|
||||||
|
url: `/api/gb_record/download/progress/${this.deviceId}/${this.channelId}/${this.stream}`
|
||||||
|
}).then((res)=> {
|
||||||
|
console.log(res)
|
||||||
|
console.log(res.data.progress)
|
||||||
|
this.streamInfo = res.data;
|
||||||
|
if (parseFloat(res.data.progress) == 1) {
|
||||||
|
this.percentage = 100;
|
||||||
|
}else {
|
||||||
|
this.percentage = (res.data.progress*100).toFixed(1);
|
||||||
|
}
|
||||||
|
if (callback)callback();
|
||||||
|
}).catch((e) =>{
|
||||||
|
|
||||||
|
});
|
||||||
|
},
|
||||||
|
close: function (){
|
||||||
|
if (this.streamInfo.progress < 100) {
|
||||||
|
this.stopDownloadRecord();
|
||||||
|
}
|
||||||
|
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',
|
||||||
|
url: '/api/gb_record/download/stop/' + this.deviceId + "/" + this.channelId+ "/" + this.stream
|
||||||
|
}).then((res)=> {
|
||||||
|
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 && res.data.msg === "success") {
|
||||||
|
// 查询进度
|
||||||
|
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) => {
|
||||||
|
if (res.data.code == 0) {
|
||||||
|
this.percentage = parseFloat(res.data.data.percentage)*100
|
||||||
|
if (res.data.data[0].percentage === '1') {
|
||||||
|
this.getProgressForFileRun = false;
|
||||||
|
window.open(res.data.data[0].downloadFile)
|
||||||
|
this.close();
|
||||||
|
}else {
|
||||||
|
if (callback)callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).catch(function (error) {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
|
@ -1,198 +0,0 @@
|
||||||
<template>
|
|
||||||
<div id="test">
|
|
||||||
<div class="timeQuery" id="timeQuery">
|
|
||||||
<div class="timeQuery-background" ></div>
|
|
||||||
<div class="timeQuery-pointer">
|
|
||||||
<div class="timeQuery-pointer-content" id="timeQueryPointer">
|
|
||||||
<div class="timeQuery-pointer-handle" @mousedown.left="mousedownHandler" ></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="timeQuery-data" >
|
|
||||||
|
|
||||||
<div class="timeQuery-data-cell" v-for="item of recordData" :style="'width:' + getDataWidth(item) + '%; left:' + getDataLeft(item) + '%'" ></div>
|
|
||||||
<!-- <div class="timeQuery-data-cell" style="width: 30%; left: 20%" @click="timeChoose"></div>-->
|
|
||||||
<!-- <div class="timeQuery-data-cell" style="width: 60%; left: 20%" @click="timeChoose"></div>-->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="timeQuery-label" >
|
|
||||||
<div class="timeQuery-label-cell" style="left: 0%">
|
|
||||||
<div class="timeQuery-label-cell-label">0</div>
|
|
||||||
</div>
|
|
||||||
<div v-for="index of timeNode" class="timeQuery-label-cell" :style="'left:' + (100.0/timeNode*index).toFixed(4) + '%'">
|
|
||||||
<div class="timeQuery-label-cell-label">{{24/timeNode * index}}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: "test",
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
mouseDown: false,
|
|
||||||
timeNode: 24,
|
|
||||||
recordData:[
|
|
||||||
{
|
|
||||||
startTime: "2021-04-18 00:00:00",
|
|
||||||
endTime: "2021-04-18 00:00:09",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
startTime: "2021-04-18 00:00:09",
|
|
||||||
endTime: "2021-04-18 01:00:05",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
startTime: "2021-04-18 02:00:01",
|
|
||||||
endTime: "2021-04-18 04:25:05",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
startTime: "2021-04-18 05:00:01",
|
|
||||||
endTime: "2021-04-18 20:00:05",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
};
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
document.body.addEventListener("mouseup", this.mouseupHandler, false)
|
|
||||||
document.body.addEventListener("mousemove", this.mousemoveHandler, false)
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
getTimeNode(){
|
|
||||||
let mine = 20
|
|
||||||
let width = document.getElementById("timeQuery").offsetWidth
|
|
||||||
if (width/20 > 24){
|
|
||||||
return 24
|
|
||||||
}else if (width/20 > 12) {
|
|
||||||
return 12
|
|
||||||
}else if (width/20 > 6) {
|
|
||||||
return 6
|
|
||||||
}
|
|
||||||
},
|
|
||||||
timeChoose(event){
|
|
||||||
console.log(event)
|
|
||||||
},
|
|
||||||
getDataWidth(item){
|
|
||||||
let startTime = new Date(item.startTime);
|
|
||||||
let endTime = new Date(item.endTime);
|
|
||||||
let result = parseFloat((endTime.getTime() - startTime.getTime())/(24*60*60*10))
|
|
||||||
// console.log(result)
|
|
||||||
return parseFloat((endTime.getTime() - startTime.getTime())/(24*60*60*10))
|
|
||||||
},
|
|
||||||
getDataLeft(item){
|
|
||||||
let startTime = new Date(item.startTime);
|
|
||||||
let differenceTime = startTime.getTime() - new Date(item.startTime.substr(0,10) + " 00:00:00").getTime()
|
|
||||||
let result = differenceTime/(24*60*60*10)
|
|
||||||
console.log(differenceTime)
|
|
||||||
console.log(result)
|
|
||||||
return parseFloat(differenceTime/(24*60*60*10));
|
|
||||||
},
|
|
||||||
mousedownHandler(event){
|
|
||||||
this.mouseDown = true
|
|
||||||
},
|
|
||||||
mousemoveHandler(event){
|
|
||||||
if (this.mouseDown){
|
|
||||||
document.getElementById("timeQueryPointer").style.left = (event.clientX - 20)+ "px"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mouseupHandler(event){
|
|
||||||
this.mouseDown = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.timeQuery{
|
|
||||||
width: 96%;
|
|
||||||
margin-left: 2%;
|
|
||||||
margin-right: 2%;
|
|
||||||
margin-top: 20%;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
.timeQuery-background{
|
|
||||||
height: 16px;
|
|
||||||
width: 100%;
|
|
||||||
background-color: #ececec;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 10;
|
|
||||||
box-shadow: #9d9d9d 0px 0px 10px inset;
|
|
||||||
}
|
|
||||||
.timeQuery-data{
|
|
||||||
height: 16px;
|
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 11;
|
|
||||||
}
|
|
||||||
.timeQuery-data-cell{
|
|
||||||
height: 10px;
|
|
||||||
background-color: #888787;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 11;
|
|
||||||
-webkit-box-shadow: #9d9d9d 0px 0px 10px inset;
|
|
||||||
margin-top: 3px;
|
|
||||||
top: 100%;
|
|
||||||
}
|
|
||||||
.timeQuery-label{
|
|
||||||
height: 16px;
|
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
|
||||||
pointer-events: none;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 11;
|
|
||||||
}
|
|
||||||
.timeQuery-label-cell{
|
|
||||||
height: 16px;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 12;
|
|
||||||
width: 0px;
|
|
||||||
border-right: 1px solid #b7b7b7;
|
|
||||||
}
|
|
||||||
.timeQuery-label-cell-label {
|
|
||||||
width: 23px;
|
|
||||||
text-align: center;
|
|
||||||
height: 18px;
|
|
||||||
margin-left: -10px;
|
|
||||||
margin-top: -30px;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
.timeQuery-pointer{
|
|
||||||
width: 0px;
|
|
||||||
height: 18px;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
.timeQuery-pointer-content{
|
|
||||||
width: 0px;
|
|
||||||
height: 70px;
|
|
||||||
position: absolute;
|
|
||||||
border-right: 2px solid #f60303;
|
|
||||||
z-index: 14;
|
|
||||||
top: -30px;
|
|
||||||
}
|
|
||||||
.timeQuery-pointer-handle {
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
border-top: 12px solid transparent;
|
|
||||||
border-right: 12px solid transparent;
|
|
||||||
border-bottom: 20px solid #ff0909;
|
|
||||||
border-left: 12px solid transparent;
|
|
||||||
cursor: no-drop;
|
|
||||||
position: absolute;
|
|
||||||
left: -11px;
|
|
||||||
top: 50px;
|
|
||||||
}
|
|
||||||
/*.timeQuery-cell:after{*/
|
|
||||||
/* content: "";*/
|
|
||||||
/* height: 14px;*/
|
|
||||||
/* border: 1px solid #e70303;*/
|
|
||||||
/* position: absolute;*/
|
|
||||||
/*}*/
|
|
||||||
</style>
|
|
|
@ -1,190 +0,0 @@
|
||||||
<template>
|
|
||||||
<div id="test2">
|
|
||||||
<div class="timeQuery" style="width: 100%; height: 300px" id="timeQuery">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
import * as echarts from 'echarts';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "test2",
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
};
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
var base = +new Date("2021-02-02 00:00:00");
|
|
||||||
var oneDay = 24 * 3600 * 1000;
|
|
||||||
|
|
||||||
var data = [[base, 10]];
|
|
||||||
|
|
||||||
for (var i = 1; i < 24; i++) {
|
|
||||||
var now = new Date(base += oneDay);
|
|
||||||
data.push([
|
|
||||||
new Date("2021-02-02 " + i+":00:00"), 10
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
// 基于准备好的dom,初始化echarts实例
|
|
||||||
var myChart = echarts.init(document.getElementById('timeQuery'));
|
|
||||||
let option = {
|
|
||||||
|
|
||||||
toolbox: {
|
|
||||||
feature: {
|
|
||||||
dataZoom: {
|
|
||||||
yAxisIndex: 'none'
|
|
||||||
},
|
|
||||||
restore: {},
|
|
||||||
saveAsImage: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'time',
|
|
||||||
boundaryGap: false
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
type: 'value',
|
|
||||||
show: false,
|
|
||||||
splitLine:{show: false}, //去除网格线
|
|
||||||
boundaryGap: [0, '100%']
|
|
||||||
},
|
|
||||||
dataZoom: [{
|
|
||||||
type: 'inside',
|
|
||||||
start: 0,
|
|
||||||
end: 20
|
|
||||||
}, {
|
|
||||||
start: 0,
|
|
||||||
end: 20
|
|
||||||
}],
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
name: '模拟数据',
|
|
||||||
type: 'line',
|
|
||||||
smooth: false,
|
|
||||||
symbol: 'none',
|
|
||||||
areaStyle: {},
|
|
||||||
data: data
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
// 绘制图表
|
|
||||||
myChart.setOption(option);
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
getTimeNode(){
|
|
||||||
let mine = 20
|
|
||||||
let width = document.getElementById("timeQuery").offsetWidth
|
|
||||||
if (width/20 > 24){
|
|
||||||
return 24
|
|
||||||
}else if (width/20 > 12) {
|
|
||||||
return 12
|
|
||||||
}else if (width/20 > 6) {
|
|
||||||
return 6
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hoveEvent(event){
|
|
||||||
console.log(2222222)
|
|
||||||
console.log(event)
|
|
||||||
},
|
|
||||||
timeChoose(event){
|
|
||||||
console.log(event)
|
|
||||||
},
|
|
||||||
getDataWidth(item){
|
|
||||||
let startTime = new Date(item.startTime);
|
|
||||||
let endTime = new Date(item.endTime);
|
|
||||||
let result = parseFloat((endTime.getTime() - startTime.getTime())/(24*60*60*10))
|
|
||||||
// console.log(result)
|
|
||||||
return parseFloat((endTime.getTime() - startTime.getTime())/(24*60*60*10))
|
|
||||||
},
|
|
||||||
getDataLeft(item){
|
|
||||||
let startTime = new Date(item.startTime);
|
|
||||||
let differenceTime = startTime.getTime() - new Date(item.startTime.substr(0,10) + " 00:00:00").getTime()
|
|
||||||
let result = differenceTime/(24*60*60*10)
|
|
||||||
console.log(differenceTime)
|
|
||||||
console.log(result)
|
|
||||||
return parseFloat(differenceTime/(24*60*60*10));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.timeQuery{
|
|
||||||
width: 96%;
|
|
||||||
margin-left: 2%;
|
|
||||||
margin-right: 2%;
|
|
||||||
margin-top: 20%;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
.timeQuery-background{
|
|
||||||
height: 16px;
|
|
||||||
width: 100%;
|
|
||||||
background-color: #ececec;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 10;
|
|
||||||
box-shadow: #9d9d9d 0px 0px 10px inset;
|
|
||||||
}
|
|
||||||
.timeQuery-data{
|
|
||||||
height: 16px;
|
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 11;
|
|
||||||
}
|
|
||||||
.timeQuery-data-cell{
|
|
||||||
height: 10px;
|
|
||||||
background-color: #888787;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 11;
|
|
||||||
-webkit-box-shadow: #9d9d9d 0px 0px 10px inset;
|
|
||||||
margin-top: 3px;
|
|
||||||
}
|
|
||||||
.timeQuery-label{
|
|
||||||
height: 16px;
|
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
|
||||||
pointer-events: none;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 11;
|
|
||||||
}
|
|
||||||
.timeQuery-label-cell{
|
|
||||||
height: 16px;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 12;
|
|
||||||
width: 0px;
|
|
||||||
border-right: 1px solid #b7b7b7;
|
|
||||||
}
|
|
||||||
.timeQuery-label-cell-label {
|
|
||||||
width: 23px;
|
|
||||||
text-align: center;
|
|
||||||
height: 18px;
|
|
||||||
margin-left: -10px;
|
|
||||||
margin-top: -30px;
|
|
||||||
color: #444;
|
|
||||||
}
|
|
||||||
.timeQuery-pointer{
|
|
||||||
width: 0px;
|
|
||||||
height: 18px;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
.timeQuery-pointer-content{
|
|
||||||
width: 0px;
|
|
||||||
height: 16px;
|
|
||||||
position: absolute;
|
|
||||||
border-right: 3px solid #f60303;
|
|
||||||
z-index: 14;
|
|
||||||
}
|
|
||||||
/*.timeQuery-cell:after{*/
|
|
||||||
/* content: "";*/
|
|
||||||
/* height: 14px;*/
|
|
||||||
/* border: 1px solid #e70303;*/
|
|
||||||
/* position: absolute;*/
|
|
||||||
/*}*/
|
|
||||||
</style>
|
|
|
@ -11,7 +11,6 @@ import login from '../components/Login.vue'
|
||||||
import parentPlatformList from '../components/ParentPlatformList.vue'
|
import parentPlatformList from '../components/ParentPlatformList.vue'
|
||||||
import cloudRecord from '../components/CloudRecord.vue'
|
import cloudRecord from '../components/CloudRecord.vue'
|
||||||
import mediaServerManger from '../components/MediaServerManger.vue'
|
import mediaServerManger from '../components/MediaServerManger.vue'
|
||||||
import test from '../components/test.vue'
|
|
||||||
import web from '../components/setting/Web.vue'
|
import web from '../components/setting/Web.vue'
|
||||||
import sip from '../components/setting/Sip.vue'
|
import sip from '../components/setting/Sip.vue'
|
||||||
import media from '../components/setting/Media.vue'
|
import media from '../components/setting/Media.vue'
|
||||||
|
@ -96,11 +95,6 @@ export default new VueRouter({
|
||||||
name: 'media',
|
name: 'media',
|
||||||
component: media,
|
component: media,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/test',
|
|
||||||
name: 'test',
|
|
||||||
component: test,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/play/wasm/:url',
|
path: '/play/wasm/:url',
|
||||||
name: 'wasmPlayer',
|
name: 'wasmPlayer',
|
||||||
|
|
Loading…
Reference in New Issue