| | |
| | | import com.ard.common.core.domain.RtpServerParam; |
| | | import com.ard.common.core.enums.LiveStreamType; |
| | | import com.ard.common.core.utils.DateUtils; |
| | | import com.ard.common.core.utils.file.FileMultipartFile; |
| | | import com.ard.gb28181.api.RemoteGb28181Service; |
| | | import com.ard.gb28181.api.domain.Device; |
| | | import com.ard.qs.api.RemoteQsDeviceService; |
| | | import com.ard.qs.api.domain.QsDevice; |
| | | import com.ard.system.api.RemoteFileService; |
| | | import com.ard.system.api.domain.SysFile; |
| | | import com.ard.work.api.RemoteCameraService; |
| | | import com.ard.work.api.RemoteChannelService; |
| | | import com.ard.work.api.domian.ArdChannel; |
| | | import com.ard.zlm.api.domain.*; |
| | | import com.ard.zlm.api.hook.OriginType; |
| | | import com.ard.zlm.common.InviteErrorCode; |
| | |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.Assert; |
| | | import org.springframework.util.DigestUtils; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import java.io.File; |
| | | import java.io.FileInputStream; |
| | | import java.nio.file.Files; |
| | | import java.nio.file.Paths; |
| | | import java.util.*; |
| | | |
| | | /** |
| | |
| | | @Slf4j |
| | | @Service |
| | | public class MediaServerServiceImpl implements IMediaServerService { |
| | | |
| | | @Resource |
| | | private RemoteFileService remoteFileService; |
| | | @Resource |
| | | private MediaServerMapper mediaServerMapper; |
| | | |
| | |
| | | |
| | | @Resource |
| | | private RemoteQsDeviceService remoteQsDeviceService; |
| | | |
| | | @Resource |
| | | private RemoteChannelService remoteChannelService; |
| | | |
| | | @Resource |
| | | private ZLMRESTfulUtils zlmresTfulUtils; |
| | |
| | | callback.run(InviteErrorCode.FAIL.getCode(), "无可用的节点", null); |
| | | return; |
| | | } |
| | | // R<QsDevice> devicer = remoteQsDeviceService.getQsDeviceInfo(streamPullPlay.getDeviceId(), SecurityConstants |
| | | // .INNER); |
| | | // if (devicer.getCode() != Constants.SUCCESS) { |
| | | // throw new RuntimeException("获取设备信息失败" + streamPullPlay.getDeviceId()); |
| | | // } |
| | | // |
| | | // if (devicer.getData() == null) { |
| | | // throw new RuntimeException("设备不存在" + streamPullPlay.getDeviceId()); |
| | | // } |
| | | // |
| | | // if ("OFFLINE".equals(devicer.getData().getDeviceStatus())) { |
| | | // throw new RuntimeException("设备不在线" + streamPullPlay.getDeviceId()); |
| | | // } |
| | | R<ArdChannel> channel = remoteChannelService.getInfo(streamPullPlay.getChannelId(), SecurityConstants.INNER); |
| | | if (channel.getCode() != Constants.SUCCESS) { |
| | | throw new RuntimeException("获取通道信息失败" + streamPullPlay.getChannelId()); |
| | | } |
| | | |
| | | if (channel.getData() == null) { |
| | | throw new RuntimeException("通道不存在" + streamPullPlay.getChannelId()); |
| | | } |
| | | |
| | | StreamInfo stream = getStreamInfoByAppAndStreamWithCheck(streamPullPlay.getApp(), streamPullPlay.getStream(), |
| | | mediaServer.getId(), null, false); |
| | |
| | | callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo); |
| | | subscribe.removeSubscribe(rtpHook); |
| | | |
| | | // QsDevice qsDevice = new QsDevice(); |
| | | // qsDevice.setId(streamPullPlay.getDeviceId()); |
| | | // qsDevice.setSnap(filePath); |
| | | // R<Boolean> r = remoteQsDeviceService.updateQsDevice(qsDevice, SecurityConstants.INNER); |
| | | // if (r.getCode() != Constants.SUCCESS) { |
| | | // throw new RuntimeException("更新设备失败"); |
| | | // } |
| | | ArdChannel ardChannel = new ArdChannel(); |
| | | ardChannel.setId(streamPullPlay.getChannelId()); |
| | | ardChannel.setSnapUrl(filePath); |
| | | R<Boolean> r = remoteChannelService.update(ardChannel, SecurityConstants.INNER); |
| | | if (r.getCode() != Constants.SUCCESS) { |
| | | throw new RuntimeException("更新设备失败"); |
| | | } |
| | | }); |
| | | |
| | | IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType()); |
| | |
| | | } |
| | | |
| | | String key = mediaNodeServerService.startProxy(mediaServer, streamPullPlay); |
| | | // QsDevice qsDevice = new QsDevice(); |
| | | // qsDevice.setId(streamPullPlay.getDeviceId()); |
| | | // qsDevice.setStreamKey(key); |
| | | // qsDevice.setMediaServerId(mediaServer.getId()); |
| | | // qsDevice.setStreamStatus("1"); |
| | | // R<Boolean> r = remoteQsDeviceService.updateQsDevice(qsDevice, SecurityConstants.INNER); |
| | | // if (r.getCode() != Constants.SUCCESS) { |
| | | // log.error("更新设备失败"); |
| | | // callback.run(InviteErrorCode.FAIL.getCode(), "更新设备失败", null); |
| | | // } |
| | | ArdChannel ardChannel = new ArdChannel(); |
| | | ardChannel.setId(streamPullPlay.getChannelId()); |
| | | ardChannel.setStreamKey(key); |
| | | ardChannel.setMediaServerId(mediaServer.getId()); |
| | | //ardChannel.setStreamStatus("1"); |
| | | R<Boolean> r = remoteChannelService.update(ardChannel, SecurityConstants.INNER); |
| | | if (r.getCode() != Constants.SUCCESS) { |
| | | log.error("更新设备失败"); |
| | | callback.run(InviteErrorCode.FAIL.getCode(), "更新设备失败", null); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | stopProxy(mediaServer, streamPullPlay.getStreamKey()); |
| | | |
| | | QsDevice qsDevice = new QsDevice(); |
| | | qsDevice.setId(streamPullPlay.getDeviceId()); |
| | | qsDevice.setStreamKey(""); |
| | | qsDevice.setMediaServerId(""); |
| | | qsDevice.setStreamStatus("0"); |
| | | R<Boolean> r = remoteQsDeviceService.updateQsDevice(qsDevice, SecurityConstants.INNER); |
| | | ArdChannel ardChannel = new ArdChannel(); |
| | | ardChannel.setId(streamPullPlay.getChannelId()); |
| | | ardChannel.setStreamKey(""); |
| | | ardChannel.setMediaServerId(""); |
| | | // ardChannel.setStreamStatus("0"); |
| | | R<Boolean> r = remoteChannelService.update(ardChannel, SecurityConstants.INNER); |
| | | if (r.getCode() != Constants.SUCCESS) { |
| | | throw new RuntimeException("更新设备失败"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 点播成功时调用截图 |
| | | * |
| | | * @param mediaServer media |
| | | * @param app app |
| | | * @param stream 流id |
| | | */ |
| | | //@Override |
| | | // public String snapOnPlay1(ZlmMediaServer mediaServer, String app, String stream) { |
| | | // String fileName = app + "-" + stream + ".jpg"; |
| | | // // 请求截图 |
| | | // log.info("[请求截图]: " + fileName); |
| | | // |
| | | // IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType()); |
| | | // if (mediaNodeServerService == null) { |
| | | // log.info("[getSnap] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType()); |
| | | // throw new RuntimeException("[getSnap] 失败, mediaServer的类型: " + mediaServer.getType() + ",未找到对应的实现类"); |
| | | // } |
| | | // String filePath = fileDomain + filePrefix + "/snap/" + fileName; |
| | | // mediaNodeServerService.getSnap(mediaServer, app, stream, 30, 300, this.filePath + "/snap", fileName); |
| | | // return filePath; |
| | | // } |
| | | /** |
| | | * 点播成功时调用截图 |
| | | * |
| | |
| | | log.info("[getSnap] 失败, mediaServer的类型: {},未找到对应的实现类", mediaServer.getType()); |
| | | throw new RuntimeException("[getSnap] 失败, mediaServer的类型: " + mediaServer.getType() + ",未找到对应的实现类"); |
| | | } |
| | | String filePath = fileDomain + filePrefix + "/snap/" + fileName; |
| | | mediaNodeServerService.getSnap(mediaServer, app, stream, 15, 1, this.filePath + "/snap", fileName); |
| | | return filePath; |
| | | } |
| | | |
| | | // 生成临时文件路径(用于 FFmpeg 截图) |
| | | String tempDir = System.getProperty("java.io.tmpdir") + "/snap_temp/"; |
| | | File tempDirFile = new File(tempDir); |
| | | if (!tempDirFile.exists()) { |
| | | tempDirFile.mkdirs(); |
| | | } |
| | | String tempFilePath = tempDir + fileName; |
| | | |
| | | try { |
| | | // 1. 获取截图到临时文件 |
| | | mediaNodeServerService.getSnap(mediaServer, app, stream, 30, 300, tempDir, fileName); |
| | | // 2. 检查临时文件是否存在 |
| | | File tempFile = new File(tempFilePath); |
| | | if (!tempFile.exists()) { |
| | | log.error("[截图失败] 临时文件不存在: {}", tempFilePath); |
| | | return null; |
| | | } |
| | | |
| | | // 3. 使用 FileMultipartFile 转换为 MultipartFile |
| | | MultipartFile multipartFile = new FileMultipartFile( |
| | | tempFile, |
| | | fileName, |
| | | "image/jpeg" |
| | | ); |
| | | |
| | | // 3. 调用文件上传接口,上传到 MinIO(bucketName 可以固定为 "snap" 或动态传入) |
| | | R<SysFile> result = remoteFileService.upload(multipartFile, "snap"); |
| | | |
| | | // 4. 清理临时文件 |
| | | Files.deleteIfExists(Paths.get(tempFilePath)); |
| | | |
| | | // 5. 返回 URL |
| | | if (result.getCode() == Constants.SUCCESS && result.getData() != null) { |
| | | String url = result.getData().getUrl(); |
| | | log.info("[截图上传成功] URL: {}", url); |
| | | return url; |
| | | } else { |
| | | log.error("[截图上传失败] {}", result.getMsg()); |
| | | return null; |
| | | } |
| | | |
| | | } catch (Exception e) { |
| | | log.error("[截图失败] ", e); |
| | | return null; |
| | | } |
| | | } |
| | | /** |
| | | * 获取截图 |
| | | * |
| | |
| | | /** |
| | | * 开始播放 |
| | | * |
| | | * @param device 设备信息 |
| | | * @param ardChannel 通道信息 |
| | | * @param record 是否录制 |
| | | * @param callback 回调 |
| | | */ |
| | | @Override |
| | | public void play(QsDevice device, Boolean record, ErrorCallback<StreamInfo> callback) { |
| | | public void play(ArdChannel ardChannel, Boolean record, ErrorCallback<StreamInfo> callback) { |
| | | ZlmMediaServer mediaServer = getMediaServerForMinimumLoad(null); |
| | | |
| | | if (mediaServer == null) { |
| | |
| | | } |
| | | |
| | | // 播放海康sdk/播放海康isup/播放大华sdk |
| | | if (LiveStreamType.HIK_SDK.getCode().equals(device.getType()) || LiveStreamType.HIK_ISUP.getCode().equals(device.getType()) || LiveStreamType.DAHUA_SDK.getCode().equals(device.getType())) { |
| | | RTPServerParam rtpServerParam = new RTPServerParam(); |
| | | if (LiveStreamType.HIK_SDK.getCode().equals(device.getType())) { |
| | | rtpServerParam.setApp("haikang"); |
| | | } else if (LiveStreamType.HIK_ISUP.getCode().equals(device.getType())) { |
| | | rtpServerParam.setApp("haikang_isup"); |
| | | } else if (LiveStreamType.DAHUA_SDK.getCode().equals(device.getType())) { |
| | | rtpServerParam.setApp("dahua"); |
| | | } |
| | | |
| | | rtpServerParam.setStreamId(device.getDeviceCode()); |
| | | rtpServerParam.setTcpMode(0); |
| | | rtpServerParam.setType(device.getType()); |
| | | rtpServerParam.setId(device.getId()); |
| | | System.out.println(rtpServerParam); |
| | | play(mediaServer, rtpServerParam, device, null, callback); |
| | | if (LiveStreamType.HIK_SDK.getCode().equals(ardChannel.getType()) || LiveStreamType.HIK_ISUP.getCode().equals(ardChannel.getType()) || LiveStreamType.DAHUA_SDK.getCode().equals(ardChannel.getType())) { |
| | | // RTPServerParam rtpServerParam = new RTPServerParam(); |
| | | // if (LiveStreamType.HIK_SDK.getCode().equals(device.getType())) { |
| | | // rtpServerParam.setApp("haikang"); |
| | | // } else if (LiveStreamType.HIK_ISUP.getCode().equals(device.getType())) { |
| | | // rtpServerParam.setApp("haikang_isup"); |
| | | // } else if (LiveStreamType.DAHUA_SDK.getCode().equals(device.getType())) { |
| | | // rtpServerParam.setApp("dahua"); |
| | | // } |
| | | // |
| | | // rtpServerParam.setStreamId(device.getDeviceCode()); |
| | | // rtpServerParam.setTcpMode(0); |
| | | // rtpServerParam.setType(device.getType()); |
| | | // rtpServerParam.setId(device.getId()); |
| | | // System.out.println(rtpServerParam); |
| | | // play(mediaServer, rtpServerParam, device, null, callback); |
| | | } |
| | | |
| | | // rtsp/rtmp/flv/hls/onvif |
| | | if (LiveStreamType.RTSP.getCode().equals(device.getType()) || LiveStreamType.RTMP.getCode().equals(device.getType()) || LiveStreamType.FLV.getCode().equals(device.getType()) || LiveStreamType.HLS.getCode().equals(device.getType()) || LiveStreamType.ONVIF.getCode().equals(device.getType())) { |
| | | if (LiveStreamType.RTSP.getCode().equals(ardChannel.getType()) || LiveStreamType.RTMP.getCode().equals(ardChannel.getType()) || LiveStreamType.FLV.getCode().equals(ardChannel.getType()) || LiveStreamType.HLS.getCode().equals(ardChannel.getType()) || LiveStreamType.ONVIF.getCode().equals(ardChannel.getType())) { |
| | | StreamPullPlay streamPullPlay = new StreamPullPlay(); |
| | | streamPullPlay.setDeviceId(device.getId()); |
| | | streamPullPlay.setStream(device.getDeviceCode()); |
| | | streamPullPlay.setUrl(device.getLiveAddress()); |
| | | streamPullPlay.setEnable_mp4("1".equals(device.getEnableMp4())); |
| | | streamPullPlay.setEnable_audio("1".equals(device.getEnableAudio())); |
| | | streamPullPlay.setChannelId(ardChannel.getId()); |
| | | streamPullPlay.setStream(ardChannel.getId()); |
| | | streamPullPlay.setUrl(ardChannel.getLiveAddress()); |
| | | streamPullPlay.setEnable_mp4(false); |
| | | streamPullPlay.setEnable_audio(true); |
| | | streamPullPlay.setRtp_type("1"); |
| | | streamPullPlay.setTimeOut(10); |
| | | |
| | | if (LiveStreamType.RTSP.getCode().equals(device.getType())) { |
| | | if (LiveStreamType.RTSP.getCode().equals(ardChannel.getType())) { |
| | | streamPullPlay.setApp("rtsp"); |
| | | } else if (LiveStreamType.RTMP.getCode().equals(device.getType())) { |
| | | streamPullPlay.setApp("rtmp"); |
| | | } else if (LiveStreamType.FLV.getCode().equals(device.getType())) { |
| | | streamPullPlay.setApp("flv"); |
| | | if ("ws".equals(device.getFlvType())) { |
| | | streamPullPlay.setUrl(convertWsToHttp(device.getLiveAddress())); |
| | | } |
| | | } else if (LiveStreamType.HLS.getCode().equals(device.getType())) { |
| | | streamPullPlay.setApp("hls"); |
| | | } else if (LiveStreamType.ONVIF.getCode().equals(device.getType())) { |
| | | streamPullPlay.setApp("onvif"); |
| | | } |
| | | } else if (LiveStreamType.RTMP.getCode().equals(ardChannel.getType())) { |
| | | streamPullPlay.setApp("rtmp");} |
| | | // } else if (LiveStreamType.FLV.getCode().equals(device.getType())) { |
| | | // streamPullPlay.setApp("flv"); |
| | | // if ("ws".equals(device.getFlvType())) { |
| | | // streamPullPlay.setUrl(convertWsToHttp(device.getLiveAddress())); |
| | | // } |
| | | // } else if (LiveStreamType.HLS.getCode().equals(device.getType())) { |
| | | // streamPullPlay.setApp("hls"); |
| | | // } else if (LiveStreamType.ONVIF.getCode().equals(device.getType())) { |
| | | // streamPullPlay.setApp("onvif"); |
| | | // } |
| | | |
| | | streamPullPlay(streamPullPlay, callback); |
| | | } |
| | | |
| | | // 视频文件 |
| | | if (LiveStreamType.VIDEO_FILE.getCode().equals(device.getType())) { |
| | | loadRecord(device.getId(), callback); |
| | | } |
| | | // if (LiveStreamType.VIDEO_FILE.getCode().equals(device.getType())) { |
| | | // loadRecord(device.getId(), callback); |
| | | // } |
| | | } |
| | | |
| | | /** |