添加云端录像获取视频播放地址的接口

结构优化
648540858 2024-01-04 18:29:34 +08:00
parent 3912d0b18a
commit ed67afb7a2
4 changed files with 127 additions and 12 deletions

View File

@ -406,4 +406,24 @@ public class ZLMRESTfulUtils {
param.put("name", fileName);
return sendPost(mediaServerItem, "deleteRecordDirectory",param, null);
}
public JSONObject loadMP4File(MediaServerItem mediaServerItem, String app, String stream, String file_path) {
Map<String, Object> param = new HashMap<>(1);
param.put("vhost", "__defaultVhost__");
param.put("app", app);
param.put("stream", stream);
param.put("file_path", file_path);
param.put("file_repeat", '0');
param.put("enable_hls", '1');
param.put("enable_hls_fmp4", '1');
param.put("enable_mp4", '0');
param.put("enable_rtsp", '1');
param.put("enable_rtmp", '1');
param.put("enable_ts", '1');
param.put("enable_fmp4", '1');
param.put("enable_audio", '1');
param.put("add_mute_audio", '1');
param.put("auto_close", '1');
return sendPost(mediaServerItem, "loadMP4File",param, null);
}
}

View File

@ -1,10 +1,12 @@
package com.genersoft.iot.vmp.service;
import com.alibaba.fastjson2.JSONArray;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.github.pagehelper.PageInfo;
import java.util.List;
@ -56,8 +58,5 @@ public interface ICloudRecordService {
*/
DownloadFileInfo getPlayUrlPath(Integer recordId);
/**
*
*/
DownloadFileInfo getLivePath(Integer recordId);
void getLivePath(Integer recordId, ErrorCallback<StreamInfo> callback);
}

View File

@ -2,16 +2,31 @@ package com.genersoft.iot.vmp.service.impl;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.genersoft.iot.vmp.common.InviteInfo;
import com.genersoft.iot.vmp.common.InviteSessionStatus;
import com.genersoft.iot.vmp.common.InviteSessionType;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
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.ZlmHttpHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam;
import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
import com.genersoft.iot.vmp.service.ICloudRecordService;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IMediaService;
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper;
import com.genersoft.iot.vmp.utils.CloudRecordUtils;
@ -25,6 +40,9 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import java.text.ParseException;
import java.time.*;
import java.util.*;
@ -39,6 +57,9 @@ public class CloudRecordServiceImpl implements ICloudRecordService {
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private IMediaService mediaService;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@ -46,7 +67,13 @@ public class CloudRecordServiceImpl implements ICloudRecordService {
private AssistRESTfulUtils assistRESTfulUtils;
@Autowired
private VideoStreamSessionManager streamSession;
private ZLMRESTfulUtils zlmresTfulUtils;
@Autowired
private ZlmHttpHookSubscribe subscribe;
@Autowired
private DynamicTask dynamicTask;
@Override
public PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) {
@ -239,4 +266,46 @@ public class CloudRecordServiceImpl implements ICloudRecordService {
MediaServerItem mediaServerItem = mediaServerService.getOne(recordItem.getMediaServerId());
return CloudRecordUtils.getDownloadFilePath(mediaServerItem, filePath);
}
@Override
public void getLivePath(Integer recordId, ErrorCallback<StreamInfo> callback) {
CloudRecordItem recordItem = cloudRecordServiceMapper.queryOne(recordId);
if (recordItem == null) {
throw new ControllerException(ErrorCode.ERROR400.getCode(), "资源不存在");
}
// 监听流上线
String app = "record-live";
String stream = recordItem.getId() + "";
MediaServerItem mediaServerItem = mediaServerService.getOne(recordItem.getMediaServerId());
if (mediaServerItem == null) {
throw new ControllerException(ErrorCode.ERROR400.getCode(), "录像记录使用的流媒体节点不在线");
}
StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream, recordItem.getMediaServerId(), false);
if (streamInfo != null) {
callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfo);
return;
}
String timeOutTaskKey = UUID.randomUUID().toString();
dynamicTask.startDelay(timeOutTaskKey, () -> {
// 取消订阅消息监听
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(app, stream, true, "rtsp", mediaServerItem.getId());
subscribe.removeSubscribe(hookSubscribe);
callback.run(ErrorCode.ERROR100.getCode(), "加载视频文件为视频流超时", null);
}, 10000);
HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed(app, stream, true, "rtsp", mediaServerItem.getId());
subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
dynamicTask.stop(timeOutTaskKey);
OnStreamChangedHookParam streamChangedHookParam = (OnStreamChangedHookParam)hookParam;
StreamInfo streamInfoForHook = mediaService.getStreamInfoByAppAndStream(mediaServerItem, app, stream, streamChangedHookParam.getTracks(), null);
subscribe.removeSubscribe(hookSubscribe);
callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), streamInfoForHook);
});
JSONObject jsonObject = zlmresTfulUtils.loadMP4File(mediaServerItem, app, stream, recordItem.getFilePath());
if (jsonObject == null || jsonObject.getInteger("code") != 0) {
subscribe.removeSubscribe(hookSubscribe);
dynamicTask.stop(timeOutTaskKey);
callback.run(ErrorCode.SUCCESS.getCode(),
jsonObject != null ? jsonObject.getString("msg"): "加载视频文件为视频流失败", null);
}
}
}

View File

@ -1,6 +1,7 @@
package com.genersoft.iot.vmp.vmanager.cloudRecord;
import com.alibaba.fastjson2.JSONArray;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.DynamicTask;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
@ -12,9 +13,7 @@ import com.genersoft.iot.vmp.service.ICloudRecordService;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
import com.genersoft.iot.vmp.service.bean.DownloadFileInfo;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.WVPPageInfo;
import com.genersoft.iot.vmp.vmanager.bean.RecordFile;
import com.genersoft.iot.vmp.vmanager.bean.*;
import com.github.pagehelper.PageInfo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@ -26,7 +25,11 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import javax.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
@ -47,6 +50,9 @@ public class CloudRecordController {
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private UserSetting userSetting;
@ResponseBody
@GetMapping("/date/list")
@ -265,11 +271,32 @@ public class CloudRecordController {
@ResponseBody
@GetMapping("/play/live")
@Operation(summary = "获取点播i地址")
@Operation(summary = "获取点播地址")
@Parameter(name = "recordId", description = "录像记录的ID", required = true)
public DownloadFileInfo getLivePath(
@RequestParam(required = true) Integer recordId
public DeferredResult<WVPResult<StreamContent>> getLivePath(
HttpServletRequest request, @RequestParam(required = true) Integer recordId
){
return cloudRecordService.getLivePath(recordId);
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>();
cloudRecordService.getLivePath(recordId, (code, msg, data) -> {
WVPResult<StreamContent> wvpResult = new WVPResult<>();
wvpResult.setCode(code);
wvpResult.setMsg(msg);
if (code == ErrorCode.SUCCESS.getCode()) {
if (userSetting.getUseSourceIpAsStreamIp()) {
data=data.clone();//深拷贝
String host;
try {
URL url=new URL(request.getRequestURL().toString());
host=url.getHost();
} catch (MalformedURLException e) {
host=request.getLocalAddr();
}
data.channgeStreamIp(host);
}
wvpResult.setData(new StreamContent(data));
}
result.setResult(wvpResult);
});
return result;
}
}