优化录像配置。不再使用zlm默认的http服务器

pull/800/head
648540858 2023-03-25 18:40:29 +08:00
parent 4f22994cdb
commit 3b1516afe5
9 changed files with 486 additions and 16 deletions

View File

@ -169,7 +169,10 @@ public class ProxyServletConfig {
protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
MediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
String remoteHost = String.format("http://%s:%s", mediaInfo.getStreamIp(), mediaInfo.getHttpPort());
if (mediaInfo == null) {
return null;
}
String remoteHost = String.format("http://%s:%s", mediaInfo.getStreamIp(), mediaInfo.getRecordAssistPort());
if (!ObjectUtils.isEmpty(queryStr)) {
queryStr += "&remoteHost=" + remoteHost;
}else {

View File

@ -54,6 +54,8 @@ public class UserSetting {
private String serverId = "000000";
private String recordPath = null;
private String thirdPartyGBIdReg = "[\\s\\S]*";
private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
@ -248,5 +250,11 @@ public class UserSetting {
this.refuseChannelStatusChannelFormNotify = refuseChannelStatusChannelFormNotify;
}
public String getRecordPath() {
return recordPath;
}
public void setRecordPath(String recordPath) {
this.recordPath = recordPath;
}
}

View File

@ -9,17 +9,12 @@ import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
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 {
@ -137,6 +132,11 @@ public class AssistRESTfulUtils {
return sendGet(mediaServerItem, "api/record/file/duration",param, callback);
}
public JSONObject getInfo(MediaServerItem mediaServerItem, RequestCallback callback){
Map<String, Object> param = new HashMap<>();
return sendGet(mediaServerItem, "api/record/info",param, callback);
}
public JSONObject addStreamCallInfo(MediaServerItem mediaServerItem, String app, String stream, String callId, RequestCallback callback){
Map<String, Object> param = new HashMap<>();
param.put("app",app);

View File

@ -253,6 +253,24 @@ public class ZLMHttpHookListener {
result.setEnable_mp4(true);
}
}
if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) {
logger.info("推流时发现尚未设置录像路径从assist服务中读取");
JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null);
if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) {
JSONObject dataJson = info.getJSONObject("data");
if (dataJson != null) {
String recordPath = dataJson.getString("record");
userSetting.setRecordPath(recordPath);
result.setMp4_save_path(recordPath);
// 修改zlm中的录像路径
if (mediaInfo.isAutoConfig()) {
taskExecutor.execute(() -> {
mediaServerService.setZLMConfig(mediaInfo, false);
});
}
}
}
}
return result;
}

View File

@ -10,21 +10,87 @@ public class ZLMServerConfig {
@JSONField(name = "api.secret")
private String apiSecret;
@JSONField(name = "api.snapRoot")
private String apiSnapRoot;
@JSONField(name = "api.defaultSnap")
private String apiDefaultSnap;
@JSONField(name = "ffmpeg.bin")
private String ffmpegBin;
@JSONField(name = "ffmpeg.cmd")
private String ffmpegCmd;
@JSONField(name = "ffmpeg.snap")
private String ffmpegSnap;
@JSONField(name = "ffmpeg.log")
private String ffmpegLog;
@JSONField(name = "ffmpeg.restart_sec")
private String ffmpegRestartSec;
@JSONField(name = "protocol.modify_stamp")
private String protocolModifyStamp;
@JSONField(name = "protocol.enable_audio")
private String protocolEnableAudio;
@JSONField(name = "protocol.add_mute_audio")
private String protocolAddMuteAudio;
@JSONField(name = "protocol.continue_push_ms")
private String protocolContinuePushMs;
@JSONField(name = "protocol.enable_hls")
private String protocolEnableHls;
@JSONField(name = "protocol.enable_mp4")
private String protocolEnableMp4;
@JSONField(name = "protocol.enable_rtsp")
private String protocolEnableRtsp;
@JSONField(name = "protocol.enable_rtmp")
private String protocolEnableRtmp;
@JSONField(name = "protocol.enable_ts")
private String protocolEnableTs;
@JSONField(name = "protocol.enable_fmp4")
private String protocolEnableFmp4;
@JSONField(name = "protocol.mp4_as_player")
private String protocolMp4AsPlayer;
@JSONField(name = "protocol.mp4_max_second")
private String protocolMp4MaxSecond;
@JSONField(name = "protocol.mp4_save_path")
private String protocolMp4SavePath;
@JSONField(name = "protocol.hls_save_path")
private String protocolHlsSavePath;
@JSONField(name = "protocol.hls_demand")
private String protocolHlsDemand;
@JSONField(name = "protocol.rtsp_demand")
private String protocolRtspDemand;
@JSONField(name = "protocol.rtmp_demand")
private String protocolRtmpDemand;
@JSONField(name = "protocol.ts_demand")
private String protocolTsDemand;
@JSONField(name = "protocol.fmp4_demand")
private String protocolFmp4Demand;
@JSONField(name = "general.enableVhost")
private String generalEnableVhost;
@JSONField(name = "general.mediaServerId")
private String generalMediaServerId;
@JSONField(name = "general.flowThreshold")
private String generalFlowThreshold;
@ -34,6 +100,25 @@ public class ZLMServerConfig {
@JSONField(name = "general.streamNoneReaderDelayMS")
private int generalStreamNoneReaderDelayMS;
@JSONField(name = "general.resetWhenRePlay")
private String generalResetWhenRePlay;
@JSONField(name = "general.mergeWriteMS")
private String generalMergeWriteMS;
@JSONField(name = "general.mediaServerId")
private String generalMediaServerId;
@JSONField(name = "general.wait_track_ready_ms")
private String generalWaitTrackReadyMs;
@JSONField(name = "general.wait_add_track_ms")
private String generalWaitAddTrackMs;
@JSONField(name = "general.unready_frame_cache")
private String generalUnreadyFrameCache;
@JSONField(name = "ip")
private String ip;
@ -59,6 +144,18 @@ public class ZLMServerConfig {
@JSONField(name = "hls.segNum")
private String hlsSegNum;
@JSONField(name = "hls.segRetain")
private String hlsSegRetain;
@JSONField(name = "hls.broadcastRecordTs")
private String hlsBroadcastRecordTs;
@JSONField(name = "hls.deleteDelaySec")
private String hlsDeleteDelaySec;
@JSONField(name = "hls.segKeep")
private String hlsSegKeep;
@JSONField(name = "hook.access_file_except_hls")
private String hookAccessFileExceptHLS;
@ -104,6 +201,18 @@ public class ZLMServerConfig {
@JSONField(name = "hook.on_stream_not_found")
private String hookOnStreamNotFound;
@JSONField(name = "hook.on_server_started")
private String hookOnServerStarted;
@JSONField(name = "hook.on_server_keepalive")
private String hookOnServerKeepalive;
@JSONField(name = "hook.on_send_rtp_stopped")
private String hookOnSendRtpStopped;
@JSONField(name = "hook.on_rtp_server_timeout")
private String hookOnRtpServerTimeout;
@JSONField(name = "hook.timeoutSec")
private String hookTimeoutSec;
@ -813,4 +922,292 @@ public class ZLMServerConfig {
public void setPortRange(String portRange) {
this.portRange = portRange;
}
public String getApiSnapRoot() {
return apiSnapRoot;
}
public void setApiSnapRoot(String apiSnapRoot) {
this.apiSnapRoot = apiSnapRoot;
}
public String getApiDefaultSnap() {
return apiDefaultSnap;
}
public void setApiDefaultSnap(String apiDefaultSnap) {
this.apiDefaultSnap = apiDefaultSnap;
}
public String getFfmpegSnap() {
return ffmpegSnap;
}
public void setFfmpegSnap(String ffmpegSnap) {
this.ffmpegSnap = ffmpegSnap;
}
public String getFfmpegRestartSec() {
return ffmpegRestartSec;
}
public void setFfmpegRestartSec(String ffmpegRestartSec) {
this.ffmpegRestartSec = ffmpegRestartSec;
}
public String getProtocolModifyStamp() {
return protocolModifyStamp;
}
public void setProtocolModifyStamp(String protocolModifyStamp) {
this.protocolModifyStamp = protocolModifyStamp;
}
public String getProtocolEnableAudio() {
return protocolEnableAudio;
}
public void setProtocolEnableAudio(String protocolEnableAudio) {
this.protocolEnableAudio = protocolEnableAudio;
}
public String getProtocolAddMuteAudio() {
return protocolAddMuteAudio;
}
public void setProtocolAddMuteAudio(String protocolAddMuteAudio) {
this.protocolAddMuteAudio = protocolAddMuteAudio;
}
public String getProtocolContinuePushMs() {
return protocolContinuePushMs;
}
public void setProtocolContinuePushMs(String protocolContinuePushMs) {
this.protocolContinuePushMs = protocolContinuePushMs;
}
public String getProtocolEnableHls() {
return protocolEnableHls;
}
public void setProtocolEnableHls(String protocolEnableHls) {
this.protocolEnableHls = protocolEnableHls;
}
public String getProtocolEnableMp4() {
return protocolEnableMp4;
}
public void setProtocolEnableMp4(String protocolEnableMp4) {
this.protocolEnableMp4 = protocolEnableMp4;
}
public String getProtocolEnableRtsp() {
return protocolEnableRtsp;
}
public void setProtocolEnableRtsp(String protocolEnableRtsp) {
this.protocolEnableRtsp = protocolEnableRtsp;
}
public String getProtocolEnableRtmp() {
return protocolEnableRtmp;
}
public void setProtocolEnableRtmp(String protocolEnableRtmp) {
this.protocolEnableRtmp = protocolEnableRtmp;
}
public String getProtocolEnableTs() {
return protocolEnableTs;
}
public void setProtocolEnableTs(String protocolEnableTs) {
this.protocolEnableTs = protocolEnableTs;
}
public String getProtocolEnableFmp4() {
return protocolEnableFmp4;
}
public void setProtocolEnableFmp4(String protocolEnableFmp4) {
this.protocolEnableFmp4 = protocolEnableFmp4;
}
public String getProtocolMp4AsPlayer() {
return protocolMp4AsPlayer;
}
public void setProtocolMp4AsPlayer(String protocolMp4AsPlayer) {
this.protocolMp4AsPlayer = protocolMp4AsPlayer;
}
public String getProtocolMp4MaxSecond() {
return protocolMp4MaxSecond;
}
public void setProtocolMp4MaxSecond(String protocolMp4MaxSecond) {
this.protocolMp4MaxSecond = protocolMp4MaxSecond;
}
public String getProtocolMp4SavePath() {
return protocolMp4SavePath;
}
public void setProtocolMp4SavePath(String protocolMp4SavePath) {
this.protocolMp4SavePath = protocolMp4SavePath;
}
public String getProtocolHlsSavePath() {
return protocolHlsSavePath;
}
public void setProtocolHlsSavePath(String protocolHlsSavePath) {
this.protocolHlsSavePath = protocolHlsSavePath;
}
public String getProtocolHlsDemand() {
return protocolHlsDemand;
}
public void setProtocolHlsDemand(String protocolHlsDemand) {
this.protocolHlsDemand = protocolHlsDemand;
}
public String getProtocolRtspDemand() {
return protocolRtspDemand;
}
public void setProtocolRtspDemand(String protocolRtspDemand) {
this.protocolRtspDemand = protocolRtspDemand;
}
public String getProtocolRtmpDemand() {
return protocolRtmpDemand;
}
public void setProtocolRtmpDemand(String protocolRtmpDemand) {
this.protocolRtmpDemand = protocolRtmpDemand;
}
public String getProtocolTsDemand() {
return protocolTsDemand;
}
public void setProtocolTsDemand(String protocolTsDemand) {
this.protocolTsDemand = protocolTsDemand;
}
public String getProtocolFmp4Demand() {
return protocolFmp4Demand;
}
public void setProtocolFmp4Demand(String protocolFmp4Demand) {
this.protocolFmp4Demand = protocolFmp4Demand;
}
public String getGeneralResetWhenRePlay() {
return generalResetWhenRePlay;
}
public void setGeneralResetWhenRePlay(String generalResetWhenRePlay) {
this.generalResetWhenRePlay = generalResetWhenRePlay;
}
public String getGeneralMergeWriteMS() {
return generalMergeWriteMS;
}
public void setGeneralMergeWriteMS(String generalMergeWriteMS) {
this.generalMergeWriteMS = generalMergeWriteMS;
}
public String getGeneralWaitTrackReadyMs() {
return generalWaitTrackReadyMs;
}
public void setGeneralWaitTrackReadyMs(String generalWaitTrackReadyMs) {
this.generalWaitTrackReadyMs = generalWaitTrackReadyMs;
}
public String getGeneralWaitAddTrackMs() {
return generalWaitAddTrackMs;
}
public void setGeneralWaitAddTrackMs(String generalWaitAddTrackMs) {
this.generalWaitAddTrackMs = generalWaitAddTrackMs;
}
public String getGeneralUnreadyFrameCache() {
return generalUnreadyFrameCache;
}
public void setGeneralUnreadyFrameCache(String generalUnreadyFrameCache) {
this.generalUnreadyFrameCache = generalUnreadyFrameCache;
}
public String getHlsSegRetain() {
return hlsSegRetain;
}
public void setHlsSegRetain(String hlsSegRetain) {
this.hlsSegRetain = hlsSegRetain;
}
public String getHlsBroadcastRecordTs() {
return hlsBroadcastRecordTs;
}
public void setHlsBroadcastRecordTs(String hlsBroadcastRecordTs) {
this.hlsBroadcastRecordTs = hlsBroadcastRecordTs;
}
public String getHlsDeleteDelaySec() {
return hlsDeleteDelaySec;
}
public void setHlsDeleteDelaySec(String hlsDeleteDelaySec) {
this.hlsDeleteDelaySec = hlsDeleteDelaySec;
}
public String getHlsSegKeep() {
return hlsSegKeep;
}
public void setHlsSegKeep(String hlsSegKeep) {
this.hlsSegKeep = hlsSegKeep;
}
public String getHookOnServerStarted() {
return hookOnServerStarted;
}
public void setHookOnServerStarted(String hookOnServerStarted) {
this.hookOnServerStarted = hookOnServerStarted;
}
public String getHookOnServerKeepalive() {
return hookOnServerKeepalive;
}
public void setHookOnServerKeepalive(String hookOnServerKeepalive) {
this.hookOnServerKeepalive = hookOnServerKeepalive;
}
public String getHookOnSendRtpStopped() {
return hookOnSendRtpStopped;
}
public void setHookOnSendRtpStopped(String hookOnSendRtpStopped) {
this.hookOnSendRtpStopped = hookOnSendRtpStopped;
}
public String getHookOnRtpServerTimeout() {
return hookOnRtpServerTimeout;
}
public void setHookOnRtpServerTimeout(String hookOnRtpServerTimeout) {
this.hookOnRtpServerTimeout = hookOnRtpServerTimeout;
}
}

View File

@ -5,6 +5,7 @@ public class HookResultForOnPublish extends HookResult{
private boolean enable_audio;
private boolean enable_mp4;
private int mp4_max_second;
private String mp4_save_path;
public HookResultForOnPublish() {
}
@ -41,4 +42,12 @@ public class HookResultForOnPublish extends HookResult{
public void setMp4_max_second(int mp4_max_second) {
this.mp4_max_second = mp4_max_second;
}
public String getMp4_save_path() {
return mp4_save_path;
}
public void setMp4_save_path(String mp4_save_path) {
this.mp4_save_path = mp4_save_path;
}
}

View File

@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
@ -38,6 +39,7 @@ import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.util.ObjectUtils;
import java.io.File;
import java.time.LocalDateTime;
import java.util.*;
@ -63,6 +65,9 @@ public class MediaServerServiceImpl implements IMediaServerService {
@Autowired
private UserSetting userSetting;
@Autowired
private AssistRESTfulUtils assistRESTfulUtils;
@Autowired
private ZLMRESTfulUtils zlmresTfulUtils;
@ -407,13 +412,27 @@ public class MediaServerServiceImpl implements IMediaServerService {
}
RedisUtil.set(key, serverItem);
resetOnlineServerItem(serverItem);
if (serverItem.isAutoConfig()) {
// 查看assist服务的录像路径配置
if (serverItem.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) {
JSONObject info = assistRESTfulUtils.getInfo(serverItem, null);
if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) {
JSONObject dataJson = info.getJSONObject("data");
if (dataJson != null) {
String recordPath = dataJson.getString("record");
userSetting.setRecordPath(recordPath);
}
}
}
setZLMConfig(serverItem, "0".equals(zlmServerConfig.getHookEnable()));
}
final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + serverItem.getId();
dynamicTask.stop(zlmKeepaliveKey);
dynamicTask.startDelay(zlmKeepaliveKey, new KeepAliveTimeoutRunnable(serverItem), (Math.getExponent(serverItem.getHookAliveInterval()) + 5) * 1000);
publisher.zlmOnlineEventPublish(serverItem.getId());
logger.info("[ZLM] 连接成功 {} - {}:{} ",
zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort());
}
@ -584,6 +603,13 @@ public class MediaServerServiceImpl implements IMediaServerService {
param.put("rtp_proxy.port_range", mediaServerItem.getRtpPortRange().replace(",", "-"));
}
if (userSetting.getRecordPath() != null) {
File recordPathFile = new File(userSetting.getRecordPath());
File mp4SavePathFile = recordPathFile.getParentFile().getAbsoluteFile();
param.put("protocol.mp4_save_path", mp4SavePathFile.getAbsoluteFile());
param.put("record.appName", recordPathFile.getName());
}
JSONObject responseJSON = zlmresTfulUtils.setServerConfig(mediaServerItem, param);
if (responseJSON != null && responseJSON.getInteger("code") == 0) {

View File

@ -45,7 +45,6 @@ public class DateUtil {
public static String ISO8601Toyyyy_MM_dd_HH_mm_ss(String formatTime) {
return formatter.format(formatterCompatibleISO8601.parse(formatTime));
}
/**

View File

@ -18,7 +18,7 @@
<i class="el-icon-video-camera" ></i>
{{ item.substring(0,17)}}
</el-tag>
<a class="el-icon-download" style="color: #409EFF;font-weight: 600;margin-left: 10px;" :href="`${basePath}/download.html?url=record/${recordFile.app}/${recordFile.stream}/${chooseDate}/${item}`" target="_blank" />
<a class="el-icon-download" style="color: #409EFF;font-weight: 600;margin-left: 10px;" :href="`${getFileBasePath()}/download.html?url=download/${recordFile.app}/${recordFile.stream}/${chooseDate}/${item}`" target="_blank" />
</li>
</ul>
</div>
@ -76,7 +76,7 @@
<li class="task-list-item" v-for="(item, index) in taskListEnded" :key="index">
<div class="task-list-item-box" style="height: 2rem;line-height: 2rem;">
<span>{{ item.startTime.substr(10) }}-{{item.endTime.substr(10)}}</span>
<a class="el-icon-download download-btn" :href="mediaServerPath + '/download.html?url=../' + item.recordFile" target="_blank">
<a class="el-icon-download download-btn" :href="getFileBasePath() + '/download.html?url=download/' + item.recordFile" target="_blank">
</a>
</div>
</li>
@ -107,15 +107,15 @@
import uiHeader from '../layout/UiHeader.vue'
import player from './dialog/easyPlayer.vue'
import moment from 'moment'
import axios from "axios";
export default {
name: 'app',
components: {
uiHeader, player
},
props: ['recordFile', 'mediaServerId', 'dateFiles', 'mediaServerPath'],
props: ['recordFile', 'mediaServerId', 'dateFiles'],
data() {
return {
basePath: `${this.mediaServerPath}`,
dateFilesObj: [],
detailFiles: [],
chooseDate: null,
@ -267,13 +267,23 @@
if (file == null) {
this.videoUrl = "";
}else {
// TODO
this.videoUrl = `${this.basePath}/record/${this.recordFile.app}/${this.recordFile.stream}/${this.chooseDate}/${this.choosedFile}`
this.videoUrl = `${this.getFileBasePath()}/download/${this.recordFile.app}/${this.recordFile.stream}/${this.chooseDate}/${this.choosedFile}`
console.log(this.videoUrl)
}
},
getFileBasePath(){
let basePath = ""
if (axios.defaults.baseURL.startsWith("http")) {
basePath = `${axios.defaults.baseURL}/record_proxy/${this.mediaServerId}`
}else {
basePath = `${window.location.origin}${axios.defaults.baseURL}/record_proxy/${this.mediaServerId}`
}
return basePath;
},
getDataWidth(item){
let timeForFile = this.getTimeForFile(item);
let result = (timeForFile[2])/((this.sliderMax - this.sliderMIn)*1000)