mirror of
https://gitee.com/pan648540858/wvp-GB28181-pro.git
synced 2026-05-24 05:57:49 +08:00
云端录像回放使用单文件播放
This commit is contained in:
parent
a064f27bf8
commit
fd306d8ede
@ -79,6 +79,8 @@ public class StreamInfo implements Serializable, Cloneable{
|
|||||||
private String startTime;
|
private String startTime;
|
||||||
@Schema(description = "结束时间")
|
@Schema(description = "结束时间")
|
||||||
private String endTime;
|
private String endTime;
|
||||||
|
@Schema(description = "时长(回放时使用)")
|
||||||
|
private Double duration;
|
||||||
@Schema(description = "进度(录像下载使用)")
|
@Schema(description = "进度(录像下载使用)")
|
||||||
private double progress;
|
private double progress;
|
||||||
@Schema(description = "文件下载地址(录像下载使用)")
|
@Schema(description = "文件下载地址(录像下载使用)")
|
||||||
|
|||||||
@ -232,9 +232,6 @@ public class ABLMediaNodeServerService implements IMediaNodeServerService {
|
|||||||
}else {
|
}else {
|
||||||
streamInfoResult.setWsFlv(addr, mediaServer.getWsFlvPort(),null, flvFile);
|
streamInfoResult.setWsFlv(addr, mediaServer.getWsFlvPort(),null, flvFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
streamInfoResult.setWsFlv(addr, mediaServer.getHttpPort(),mediaServer.getHttpSSlPort(), flvFile);
|
|
||||||
|
|
||||||
String mp4File = String.format("%s/%s.mp4%s", app, stream, callIdParam);
|
String mp4File = String.format("%s/%s.mp4%s", app, stream, callIdParam);
|
||||||
if ((mediaServer.getMp4Port() & 1) == 1) {
|
if ((mediaServer.getMp4Port() & 1) == 1) {
|
||||||
// 奇数端口 默认ssl端口
|
// 奇数端口 默认ssl端口
|
||||||
@ -243,7 +240,6 @@ public class ABLMediaNodeServerService implements IMediaNodeServerService {
|
|||||||
streamInfoResult.setFmp4(addr, mediaServer.getMp4Port(), null, mp4File);
|
streamInfoResult.setFmp4(addr, mediaServer.getMp4Port(), null, mp4File);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
streamInfoResult.setHls(addr, mediaServer.getHttpPort(), mediaServer.getHttpSSlPort(), app, stream, callIdParam);
|
streamInfoResult.setHls(addr, mediaServer.getHttpPort(), mediaServer.getHttpSSlPort(), app, stream, callIdParam);
|
||||||
streamInfoResult.setTs(addr, mediaServer.getHttpPort(), mediaServer.getHttpSSlPort(), app, stream, callIdParam);
|
streamInfoResult.setTs(addr, mediaServer.getHttpPort(), mediaServer.getHttpSSlPort(), app, stream, callIdParam);
|
||||||
streamInfoResult.setRtc(addr, mediaServer.getHttpPort(), mediaServer.getHttpSSlPort(), app, stream, callIdParam, isPlay);
|
streamInfoResult.setRtc(addr, mediaServer.getHttpPort(), mediaServer.getHttpSSlPort(), app, stream, callIdParam, isPlay);
|
||||||
@ -463,7 +459,14 @@ public class ABLMediaNodeServerService implements IMediaNodeServerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadMP4File(MediaServer mediaServer, String app, String stream, String date, String dateDir, ErrorCallback<StreamInfo> callback) {
|
public void loadMP4File(MediaServer mediaServer, String app, String stream, String filePath, String fileName, ErrorCallback<StreamInfo> callback) {
|
||||||
|
String buildStream = String.format("%s__ReplayFMP4RecordFile__%s", stream, fileName);
|
||||||
|
StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, app, buildStream, null, null, null, true);
|
||||||
|
callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadMP4FileForDate(MediaServer mediaServer, String app, String stream, String date, String dateDir, ErrorCallback<StreamInfo> callback) {
|
||||||
// 解析为 LocalDate
|
// 解析为 LocalDate
|
||||||
LocalDate localDate = LocalDate.parse(date, DateUtil.DateFormatter);
|
LocalDate localDate = LocalDate.parse(date, DateUtil.DateFormatter);
|
||||||
LocalDateTime startOfDay = localDate.atStartOfDay();
|
LocalDateTime startOfDay = localDate.atStartOfDay();
|
||||||
@ -478,7 +481,6 @@ public class ABLMediaNodeServerService implements IMediaNodeServerService {
|
|||||||
String resultApp = ablResult.getApp();
|
String resultApp = ablResult.getApp();
|
||||||
String resultStream = ablResult.getStream();
|
String resultStream = ablResult.getStream();
|
||||||
StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, resultApp, resultStream, null, null,null, true);
|
StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, resultApp, resultStream, null, null,null, true);
|
||||||
System.out.println(streamInfo.getRtsp());
|
|
||||||
streamInfo.setKey(ablResult.getKey());
|
streamInfo.setKey(ablResult.getKey());
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);
|
callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);
|
||||||
@ -487,7 +489,7 @@ public class ABLMediaNodeServerService implements IMediaNodeServerService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seekRecordStamp(MediaServer mediaServer, String app, String stream, String key, Double stamp, String schema) {
|
public void seekRecordStamp(MediaServer mediaServer, String app, String stream, String key, Double stamp, String schema) {
|
||||||
ABLResult ablResult = ablresTfulUtils.controlRecordPlay(mediaServer, key, "seek", ((int)(stamp/1000)) + "");
|
ABLResult ablResult = ablresTfulUtils.controlRecordPlay(mediaServer, key, "seek", "120");
|
||||||
if (ablResult.getCode() != 0) {
|
if (ablResult.getCode() != 0) {
|
||||||
log.warn("[abl-seek] 失败:{}", ablResult.getMemo());
|
log.warn("[abl-seek] 失败:{}", ablResult.getMemo());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -526,7 +526,7 @@ public class ABLRESTfulUtils {
|
|||||||
Map<String, Object> param = new HashMap<>();
|
Map<String, Object> param = new HashMap<>();
|
||||||
param.put("key", key);
|
param.put("key", key);
|
||||||
param.put("command", command);
|
param.put("command", command);
|
||||||
param.put("value", value);
|
param.put("value", Long.valueOf(value));
|
||||||
String response = sendGet(mediaServer, "controlRecordPlay", param);
|
String response = sendGet(mediaServer, "controlRecordPlay", param);
|
||||||
ABLResult ablResult = JSON.parseObject(response, ABLResult.class);
|
ABLResult ablResult = JSON.parseObject(response, ABLResult.class);
|
||||||
if (ablResult == null) {
|
if (ablResult == null) {
|
||||||
|
|||||||
@ -20,6 +20,7 @@ public class ABLResult {
|
|||||||
private String stream;
|
private String stream;
|
||||||
private String starttime;
|
private String starttime;
|
||||||
private String endtime;
|
private String endtime;
|
||||||
|
private Long duration;
|
||||||
private ABLUrls url;
|
private ABLUrls url;
|
||||||
private List<ABLRecordFile> recordFileList;
|
private List<ABLRecordFile> recordFileList;
|
||||||
|
|
||||||
|
|||||||
@ -77,7 +77,7 @@ public interface IMediaNodeServerService {
|
|||||||
|
|
||||||
List<String> listRtpServer(MediaServer mediaServer);
|
List<String> listRtpServer(MediaServer mediaServer);
|
||||||
|
|
||||||
void loadMP4File(MediaServer mediaServer, String app, String stream, String datePath, String dateDir, ErrorCallback<StreamInfo> callback);
|
void loadMP4FileForDate(MediaServer mediaServer, String app, String stream, String datePath, String dateDir, ErrorCallback<StreamInfo> callback);
|
||||||
|
|
||||||
void seekRecordStamp(MediaServer mediaServer, String app, String stream, String key, Double stamp, String schema);
|
void seekRecordStamp(MediaServer mediaServer, String app, String stream, String key, Double stamp, String schema);
|
||||||
|
|
||||||
@ -86,4 +86,6 @@ public interface IMediaNodeServerService {
|
|||||||
DownloadFileInfo getDownloadFilePath(MediaServer mediaServer, RecordInfo recordInfo);
|
DownloadFileInfo getDownloadFilePath(MediaServer mediaServer, RecordInfo recordInfo);
|
||||||
|
|
||||||
StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServer, String app, String stream, MediaInfo mediaInfo, String addr, String callId, boolean isPlay);
|
StreamInfo getStreamInfoByAppAndStream(MediaServer mediaServer, String app, String stream, MediaInfo mediaInfo, String addr, String callId, boolean isPlay);
|
||||||
|
|
||||||
|
void loadMP4File(MediaServer mediaServer, String app, String stream, String filePath, String fileName, ErrorCallback<StreamInfo> callback);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -164,11 +164,13 @@ public interface IMediaServerService {
|
|||||||
|
|
||||||
List<String> listRtpServer(MediaServer mediaServer);
|
List<String> listRtpServer(MediaServer mediaServer);
|
||||||
|
|
||||||
void loadMP4File(MediaServer mediaServer, String app, String stream, String datePath, String dateDir, ErrorCallback<StreamInfo> callback);
|
void loadMP4FileForDate(MediaServer mediaServer, String app, String stream, String datePath, String dateDir, ErrorCallback<StreamInfo> callback);
|
||||||
|
|
||||||
void seekRecordStamp(MediaServer mediaServer, String app, String stream, String key, Double stamp, String schema);
|
void seekRecordStamp(MediaServer mediaServer, String app, String stream, String key, Double stamp, String schema);
|
||||||
|
|
||||||
void setRecordSpeed(MediaServer mediaServer, String app, String stream, String key, Integer speed, String schema);
|
void setRecordSpeed(MediaServer mediaServer, String app, String stream, String key, Integer speed, String schema);
|
||||||
|
|
||||||
DownloadFileInfo getDownloadFilePath(MediaServer mediaServer, RecordInfo recordInfo);
|
DownloadFileInfo getDownloadFilePath(MediaServer mediaServer, RecordInfo recordInfo);
|
||||||
|
|
||||||
|
void loadMP4File(MediaServer mediaServer, String app, String stream, String filePath, String fileName, ErrorCallback<StreamInfo> callback);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -952,14 +952,24 @@ public class MediaServerServiceImpl implements IMediaServerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadMP4File(MediaServer mediaServer, String app, String stream, String date, String dateDir, ErrorCallback<StreamInfo> callback) {
|
public void loadMP4FileForDate(MediaServer mediaServer, String app, String stream, String date, String dateDir, ErrorCallback<StreamInfo> callback) {
|
||||||
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
|
if (mediaNodeServerService == null) {
|
||||||
|
log.info("[loadMP4FileForDate] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到mediaServer对应的实现类");
|
||||||
|
}
|
||||||
|
mediaNodeServerService.loadMP4FileForDate(mediaServer, app, stream, date, dateDir, callback);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadMP4File(MediaServer mediaServer, String app, String stream, String filePath, String fileName, ErrorCallback<StreamInfo> callback) {
|
||||||
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
|
||||||
if (mediaNodeServerService == null) {
|
if (mediaNodeServerService == null) {
|
||||||
log.info("[loadMP4File] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
log.info("[loadMP4File] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType());
|
||||||
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到mediaServer对应的实现类");
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到mediaServer对应的实现类");
|
||||||
}
|
}
|
||||||
mediaNodeServerService.loadMP4File(mediaServer, app, stream, date, dateDir, callback);
|
mediaNodeServerService.loadMP4File(mediaServer, app, stream, filePath, fileName, callback);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -22,14 +22,12 @@ import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy;
|
|||||||
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
|
||||||
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service("zlm")
|
@Service("zlm")
|
||||||
@ -515,7 +513,30 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadMP4File(MediaServer mediaServer, String app, String stream, String date, String dateDir, ErrorCallback<StreamInfo> callback) {
|
public void loadMP4File(MediaServer mediaServer, String app, String stream, String filePath, String fileName, ErrorCallback<StreamInfo> callback) {
|
||||||
|
String buildApp = "mp4_record";
|
||||||
|
String buildStream = app + "_" + stream + "_" + fileName + "_" + RandomStringUtils.randomAlphabetic(6).toLowerCase();
|
||||||
|
|
||||||
|
Hook hook = Hook.getInstance(HookType.on_media_arrival, buildApp, buildStream, mediaServer.getServerId());
|
||||||
|
subscribe.addSubscribe(hook, (hookData) -> {
|
||||||
|
StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, buildApp, buildStream, hookData.getMediaInfo(), null, null, true);
|
||||||
|
if (callback != null) {
|
||||||
|
callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ZLMResult<?> zlmResult = zlmresTfulUtils.loadMP4File(mediaServer, buildApp, buildStream, filePath);
|
||||||
|
|
||||||
|
if (zlmResult == null) {
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "请求失败");
|
||||||
|
}
|
||||||
|
if (zlmResult.getCode() != 0) {
|
||||||
|
throw new ControllerException(zlmResult.getCode(), zlmResult.getMsg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadMP4FileForDate(MediaServer mediaServer, String app, String stream, String date, String dateDir, ErrorCallback<StreamInfo> callback) {
|
||||||
String buildApp = "mp4_record";
|
String buildApp = "mp4_record";
|
||||||
String buildStream = app + "_" + stream + "_" + date;
|
String buildStream = app + "_" + stream + "_" + date;
|
||||||
MediaInfo mediaInfo = getMediaInfo(mediaServer, buildApp, buildStream);
|
MediaInfo mediaInfo = getMediaInfo(mediaServer, buildApp, buildStream);
|
||||||
|
|||||||
@ -59,11 +59,13 @@ public interface ICloudRecordService {
|
|||||||
/**
|
/**
|
||||||
* 加载录像文件,形成录像流
|
* 加载录像文件,形成录像流
|
||||||
*/
|
*/
|
||||||
void loadRecord(String app, String stream, String date, ErrorCallback<StreamInfo> callback);
|
void loadMP4FileForDate(String app, String stream, String date, ErrorCallback<StreamInfo> callback);
|
||||||
|
|
||||||
void seekRecord(String mediaServerId,String app, String stream, String key, Double seek, String schema);
|
void seekRecord(String mediaServerId,String app, String stream, String key, Double seek, String schema);
|
||||||
|
|
||||||
void setRecordSpeed(String mediaServerId, String app, String stream, String key, Integer speed, String schema);
|
void setRecordSpeed(String mediaServerId, String app, String stream, String key, Integer speed, String schema);
|
||||||
|
|
||||||
void deleteFileByIds(Set<Integer> ids);
|
void deleteFileByIds(Set<Integer> ids);
|
||||||
|
|
||||||
|
void loadMP4File(String app, String stream, int cloudRecordId, ErrorCallback<StreamInfo> callback);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -281,7 +281,36 @@ public class CloudRecordServiceImpl implements ICloudRecordService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadRecord(String app, String stream, String date, ErrorCallback<StreamInfo> callback) {
|
public void loadMP4File(String app, String stream, int cloudRecordId, ErrorCallback<StreamInfo> callback) {
|
||||||
|
|
||||||
|
CloudRecordItem recordItem = cloudRecordServiceMapper.queryOne(cloudRecordId);
|
||||||
|
if (recordItem == null) {
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "无录像");
|
||||||
|
}
|
||||||
|
String mediaServerId = recordItem.getMediaServerId();
|
||||||
|
MediaServer mediaServer = mediaServerService.getOne(mediaServerId);
|
||||||
|
if (mediaServer == null) {
|
||||||
|
log.warn("[云端录像] 播放 未找到录制的流媒体,将自动选择低负载流媒体使用");
|
||||||
|
mediaServer = mediaServerService.getMediaServerForMinimumLoad(null);
|
||||||
|
}
|
||||||
|
if (mediaServer == null) {
|
||||||
|
throw new ControllerException(ErrorCode.ERROR100.getCode(), "无可用流媒体");
|
||||||
|
}
|
||||||
|
String fileName = recordItem.getFileName().substring(0 , recordItem.getFileName().indexOf("."));
|
||||||
|
String filePath = recordItem.getFilePath();
|
||||||
|
// if (filePath != null) {
|
||||||
|
// fileName = filePath.substring(0, filePath.lastIndexOf("/"));
|
||||||
|
// }
|
||||||
|
mediaServerService.loadMP4File(mediaServer, app, stream, filePath, fileName, ((code, msg, streamInfo) -> {
|
||||||
|
if (code == ErrorCode.SUCCESS.getCode()) {
|
||||||
|
streamInfo.setDuration(recordItem.getTimeLen());
|
||||||
|
}
|
||||||
|
callback.run(code, msg, streamInfo);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadMP4FileForDate(String app, String stream, String date, ErrorCallback<StreamInfo> callback) {
|
||||||
long startTimestamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestampMs(date + " 00:00:00");
|
long startTimestamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestampMs(date + " 00:00:00");
|
||||||
long endTimestamp = startTimestamp + 24 * 60 * 60 * 1000;
|
long endTimestamp = startTimestamp + 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
@ -299,7 +328,7 @@ public class CloudRecordServiceImpl implements ICloudRecordService {
|
|||||||
if (filePath != null) {
|
if (filePath != null) {
|
||||||
dateDir = filePath.substring(0, filePath.lastIndexOf("/"));
|
dateDir = filePath.substring(0, filePath.lastIndexOf("/"));
|
||||||
}
|
}
|
||||||
mediaServerService.loadMP4File(mediaServer, app, stream, date, dateDir, callback);
|
mediaServerService.loadMP4FileForDate(mediaServer, app, stream, date, dateDir, callback);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -97,6 +97,9 @@ public class StreamContent {
|
|||||||
@Schema(description = "结束时间")
|
@Schema(description = "结束时间")
|
||||||
private String endTime;
|
private String endTime;
|
||||||
|
|
||||||
|
@Schema(description = "时长(回放时使用)")
|
||||||
|
private Double duration;
|
||||||
|
|
||||||
@Schema(description = "文件下载地址(录像下载使用)")
|
@Schema(description = "文件下载地址(录像下载使用)")
|
||||||
private DownloadFileInfo downLoadFilePath;
|
private DownloadFileInfo downLoadFilePath;
|
||||||
|
|
||||||
@ -185,6 +188,7 @@ public class StreamContent {
|
|||||||
this.startTime = streamInfo.getStartTime();
|
this.startTime = streamInfo.getStartTime();
|
||||||
this.endTime = streamInfo.getEndTime();
|
this.endTime = streamInfo.getEndTime();
|
||||||
this.progress = streamInfo.getProgress();
|
this.progress = streamInfo.getProgress();
|
||||||
|
this.duration = streamInfo.getDuration();
|
||||||
this.key = streamInfo.getKey();
|
this.key = streamInfo.getKey();
|
||||||
|
|
||||||
if (streamInfo.getDownLoadFilePath() != null) {
|
if (streamInfo.getDownLoadFilePath() != null) {
|
||||||
|
|||||||
@ -253,17 +253,17 @@ public class CloudRecordController {
|
|||||||
@Operation(summary = "加载录像文件形成播放地址")
|
@Operation(summary = "加载录像文件形成播放地址")
|
||||||
@Parameter(name = "app", description = "应用名", required = true)
|
@Parameter(name = "app", description = "应用名", required = true)
|
||||||
@Parameter(name = "stream", description = "流ID", required = true)
|
@Parameter(name = "stream", description = "流ID", required = true)
|
||||||
@Parameter(name = "date", description = "日期, 例如 2025-04-10", required = true)
|
@Parameter(name = "cloudRecordId", description = "云端录像ID", required = true)
|
||||||
public DeferredResult<WVPResult<StreamContent>> loadRecord(
|
public DeferredResult<WVPResult<StreamContent>> loadRecord(
|
||||||
HttpServletRequest request,
|
HttpServletRequest request,
|
||||||
@RequestParam(required = true) String app,
|
@RequestParam(required = true) String app,
|
||||||
@RequestParam(required = true) String stream,
|
@RequestParam(required = true) String stream,
|
||||||
@RequestParam(required = true) String date
|
@RequestParam(required = true) int cloudRecordId
|
||||||
) {
|
) {
|
||||||
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>();
|
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>();
|
||||||
|
|
||||||
result.onTimeout(()->{
|
result.onTimeout(()->{
|
||||||
log.info("[加载录像文件超时] app={}, stream={}, date={}", app, stream, date);
|
log.info("[加载录像文件超时] app={}, stream={}, cloudRecordId={}", app, stream, cloudRecordId);
|
||||||
WVPResult<StreamContent> wvpResult = new WVPResult<>();
|
WVPResult<StreamContent> wvpResult = new WVPResult<>();
|
||||||
wvpResult.setCode(ErrorCode.ERROR100.getCode());
|
wvpResult.setCode(ErrorCode.ERROR100.getCode());
|
||||||
wvpResult.setMsg("加载录像文件超时");
|
wvpResult.setMsg("加载录像文件超时");
|
||||||
@ -304,7 +304,7 @@ public class CloudRecordController {
|
|||||||
result.setResult(wvpResult);
|
result.setResult(wvpResult);
|
||||||
};
|
};
|
||||||
|
|
||||||
cloudRecordService.loadRecord(app, stream, date, callback);
|
cloudRecordService.loadMP4File(app, stream, cloudRecordId, callback);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,14 +28,14 @@ export function queryListByData(params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function loadRecord(params) {
|
export function loadRecord(params) {
|
||||||
const { app, stream, date } = params
|
const { app, stream, cloudRecordId } = params
|
||||||
return request({
|
return request({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: `/api/cloud/record/loadRecord`,
|
url: `/api/cloud/record/loadRecord`,
|
||||||
params: {
|
params: {
|
||||||
app: app,
|
app: app,
|
||||||
stream: stream,
|
stream: stream,
|
||||||
date: date
|
cloudRecordId: cloudRecordId
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,7 +46,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="playerBox">
|
<div id="playerBox">
|
||||||
<div class="playBox" style="height: calc(100% - 90px); width: 100%; background-color: #000000">
|
<div class="playBox" style="height: calc(100% - 24px); width: 100%; background-color: #000000">
|
||||||
<div v-if="playLoading" style="position: relative; left: calc(50% - 32px); top: 43%; z-index: 100;color: #fff;float: left; text-align: center;">
|
<div v-if="playLoading" style="position: relative; left: calc(50% - 32px); top: 43%; z-index: 100;color: #fff;float: left; text-align: center;">
|
||||||
<div class="el-icon-loading" />
|
<div class="el-icon-loading" />
|
||||||
<div style="width: 100%; line-height: 2rem">正在加载</div>
|
<div style="width: 100%; line-height: 2rem">正在加载</div>
|
||||||
@ -54,16 +54,18 @@
|
|||||||
<h265web ref="recordVideoPlayer" :video-url="videoUrl" :height="'calc(100vh - 250px)'" :show-button="false" @playTimeChange="showPlayTimeChange" @playStatusChange="playingChange"/>
|
<h265web ref="recordVideoPlayer" :video-url="videoUrl" :height="'calc(100vh - 250px)'" :show-button="false" @playTimeChange="showPlayTimeChange" @playStatusChange="playingChange"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="player-option-box">
|
<div class="player-option-box">
|
||||||
<VideoTimeline
|
<div class="cloud-record-show-time">
|
||||||
ref="Timeline"
|
{{showPlayTimeValue}}
|
||||||
:init-time="initTime"
|
</div>
|
||||||
:time-segments="timeSegments"
|
<div class="cloud-record-time-process">
|
||||||
:init-zoom-index="4"
|
<div v-if="streamInfo">
|
||||||
@timeChange="playTimeChange"
|
<div class="cloud-record-time-process-value" :style="playTimeValue"></div>
|
||||||
@mousedown="timelineMouseDown"
|
<div class="cloud-record-time-process-pointer" :style="playTimeTotal"></div>
|
||||||
@mouseup="mouseupTimeline"
|
</div>
|
||||||
/>
|
</div>
|
||||||
<div v-if="showTime" class="time-line-show">{{ showTimeValue }}</div>
|
<div class="cloud-record-show-time">
|
||||||
|
{{showPlayTimeTotal}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="height: 40px; background-color: #383838; display: grid; grid-template-columns: 1fr 600px 1fr">
|
<div style="height: 40px; background-color: #383838; display: grid; grid-template-columns: 1fr 600px 1fr">
|
||||||
<div style="text-align: left;">
|
<div style="text-align: left;">
|
||||||
@ -111,14 +113,13 @@
|
|||||||
<script>
|
<script>
|
||||||
|
|
||||||
import h265web from '../common/h265web.vue'
|
import h265web from '../common/h265web.vue'
|
||||||
import VideoTimeline from '../common/VideoTimeLine/index.vue'
|
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import screenfull from 'screenfull'
|
import screenfull from 'screenfull'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CloudRecordDetail',
|
name: 'CloudRecordDetail',
|
||||||
components: {
|
components: {
|
||||||
h265web, VideoTimeline
|
h265web
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -179,8 +180,18 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showTimeValue() {
|
|
||||||
return moment(this.playTime).format('YYYY-MM-DD HH:mm:ss')
|
showPlayTimeValue() {
|
||||||
|
return this.streamInfo !== null ? moment(this.playerTime).format('mm:ss') : '--:--'
|
||||||
|
},
|
||||||
|
playTimeValue() {
|
||||||
|
return { width: this.playerTime/this.streamInfo.duration * 100 + '%' }
|
||||||
|
},
|
||||||
|
showPlayTimeTotal() {
|
||||||
|
return this.streamInfo !== null ? moment(this.streamInfo.duration).format('mm:ss') : '--:--'
|
||||||
|
},
|
||||||
|
playTimeTotal() {
|
||||||
|
return { left: `calc(${this.playerTime/this.streamInfo.duration * 100}% - 6px)` }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -217,15 +228,14 @@ export default {
|
|||||||
this.chooseFile(this.chooseFileIndex + 1)
|
this.chooseFile(this.chooseFileIndex + 1)
|
||||||
},
|
},
|
||||||
changePlaySpeed(speed) {
|
changePlaySpeed(speed) {
|
||||||
console.log(speed)
|
|
||||||
// 倍速播放
|
// 倍速播放
|
||||||
this.playSpeed = speed
|
this.playSpeed = speed
|
||||||
this.$store.dispatch('cloudRecord/speed', {
|
this.$store.dispatch('cloudRecord/speed', {
|
||||||
mediaServerId: this.streamInfo.mediaServerId,
|
mediaServerId: this.streamInfo.mediaServerId,
|
||||||
app: this.streamInfo.app,
|
app: this.streamInfo.app,
|
||||||
stream: this.streamInfo.stream,
|
stream: this.streamInfo.stream,
|
||||||
|
key: this.streamInfo.key,
|
||||||
speed: this.playSpeed,
|
speed: this.playSpeed,
|
||||||
seek: this.playSeekValue,
|
|
||||||
schema: 'ts'
|
schema: 'ts'
|
||||||
})
|
})
|
||||||
this.$refs.recordVideoPlayer.setPlaybackRate(this.playSpeed)
|
this.$refs.recordVideoPlayer.setPlaybackRate(this.playSpeed)
|
||||||
@ -243,10 +253,12 @@ export default {
|
|||||||
stopPLay() {
|
stopPLay() {
|
||||||
// 停止
|
// 停止
|
||||||
this.$refs.recordVideoPlayer.destroy()
|
this.$refs.recordVideoPlayer.destroy()
|
||||||
|
this.streamInfo = null
|
||||||
},
|
},
|
||||||
pausePlay() {
|
pausePlay() {
|
||||||
// 暂停
|
// 暂停
|
||||||
this.$refs.recordVideoPlayer.pause()
|
this.$refs.recordVideoPlayer.pause()
|
||||||
|
// TODO
|
||||||
},
|
},
|
||||||
play() {
|
play() {
|
||||||
if (this.$refs.recordVideoPlayer.loaded) {
|
if (this.$refs.recordVideoPlayer.loaded) {
|
||||||
@ -272,6 +284,9 @@ export default {
|
|||||||
this.isFullScreen = true
|
this.isFullScreen = true
|
||||||
},
|
},
|
||||||
dateChange() {
|
dateChange() {
|
||||||
|
this.$refs.recordVideoPlayer.destroy()
|
||||||
|
this.streamInfo = null
|
||||||
|
this.chooseFileIndex = null
|
||||||
this.detailFiles = []
|
this.detailFiles = []
|
||||||
this.currentPage = 1
|
this.currentPage = 1
|
||||||
const chooseFullDate = new Date(this.chooseDate + ' ' + this.timeFormat)
|
const chooseFullDate = new Date(this.chooseDate + ' ' + this.timeFormat)
|
||||||
@ -331,32 +346,25 @@ export default {
|
|||||||
},
|
},
|
||||||
chooseFile(index) {
|
chooseFile(index) {
|
||||||
this.chooseFileIndex = index
|
this.chooseFileIndex = index
|
||||||
let timeLength = 0
|
|
||||||
for (let i = 0; i < this.detailFiles.length; i++) {
|
|
||||||
if (i < index) {
|
|
||||||
timeLength += this.detailFiles[i].timeLen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.playSeekValue = timeLength
|
|
||||||
this.playRecord()
|
this.playRecord()
|
||||||
},
|
},
|
||||||
playRecord() {
|
playRecord() {
|
||||||
if (!this.$refs.recordVideoPlayer.playing) {
|
if (this.$refs.recordVideoPlayer.playing) {
|
||||||
this.$refs.recordVideoPlayer.destroy()
|
this.$refs.recordVideoPlayer.destroy()
|
||||||
}
|
}
|
||||||
this.$store.dispatch('cloudRecord/loadRecord', {
|
this.$store.dispatch('cloudRecord/loadRecord', {
|
||||||
app: this.app,
|
app: this.app,
|
||||||
stream: this.stream,
|
stream: this.stream,
|
||||||
date: this.chooseDate
|
cloudRecordId: this.detailFiles[this.chooseFileIndex].id
|
||||||
})
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
this.streamInfo = data
|
this.streamInfo = data
|
||||||
if (location.protocol === 'https:') {
|
if (location.protocol === 'https:') {
|
||||||
this.videoUrl = data['https_fmp4'] + '&time=' + new Date().getTime()
|
this.videoUrl = data['wss_flv']
|
||||||
} else {
|
} else {
|
||||||
this.videoUrl = data['fmp4'] + '&time=' + new Date().getTime()
|
this.videoUrl = data['ws_flv']
|
||||||
}
|
}
|
||||||
this.seekRecord()
|
this.playerTime = 0
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
@ -364,6 +372,7 @@ export default {
|
|||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.playLoading = false
|
this.playLoading = false
|
||||||
})
|
})
|
||||||
|
|
||||||
},
|
},
|
||||||
seekRecord() {
|
seekRecord() {
|
||||||
this.$store.dispatch('cloudRecord/seek', {
|
this.$store.dispatch('cloudRecord/seek', {
|
||||||
@ -566,13 +575,38 @@ export default {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
.player-option-box {
|
.player-option-box {
|
||||||
height: 50px
|
height: 20px;
|
||||||
|
width: 100%;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 50px auto 50px;
|
||||||
|
background-color: rgb(0, 0, 0);
|
||||||
}
|
}
|
||||||
.time-line-show {
|
.cloud-record-time-process {
|
||||||
|
width: 100%;
|
||||||
|
height: 8px;
|
||||||
|
margin: 6px 0 ;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #505050;
|
||||||
|
background-color: rgb(56, 56, 56);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.cloud-record-show-time {
|
||||||
|
color: #FFFFFF;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px
|
||||||
|
}
|
||||||
|
.cloud-record-time-process-value {
|
||||||
|
width: 100%;
|
||||||
|
height: 6px;
|
||||||
|
background-color: rgb(162, 162, 162);
|
||||||
|
}
|
||||||
|
.cloud-record-time-process-pointer {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
background-color: rgb(192 190 190);
|
||||||
|
border-radius: 5px;
|
||||||
position: relative;
|
position: relative;
|
||||||
color: rgba(250, 249, 249, 0.89);
|
top: -9px;
|
||||||
left: calc(50% - 85px);
|
|
||||||
top: -72px;
|
|
||||||
text-shadow: 1px 0 #5f6b7c, -1px 0 #5f6b7c, 0 1px #5f6b7c, 0 -1px #5f6b7c, 1.1px 1.1px #5f6b7c, 1.1px -1.1px #5f6b7c, -1.1px 1.1px #5f6b7c, -1.1px -1.1px #5f6b7c;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user