PlayController.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. package com.genersoft.iot.vmp.vmanager.play;
  2. import com.genersoft.iot.vmp.common.StreamInfo;
  3. import com.genersoft.iot.vmp.conf.MediaServerConfig;
  4. import com.genersoft.iot.vmp.gb28181.bean.Device;
  5. import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
  6. import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  7. import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  8. import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  9. import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult;
  10. import com.genersoft.iot.vmp.vmanager.service.IMediaService;
  11. import com.genersoft.iot.vmp.vmanager.service.IPlayService;
  12. import org.slf4j.Logger;
  13. import org.slf4j.LoggerFactory;
  14. import org.springframework.beans.factory.annotation.Autowired;
  15. import org.springframework.http.HttpStatus;
  16. import org.springframework.http.ResponseEntity;
  17. import org.springframework.web.bind.annotation.CrossOrigin;
  18. import org.springframework.web.bind.annotation.GetMapping;
  19. import org.springframework.web.bind.annotation.PathVariable;
  20. import org.springframework.web.bind.annotation.PostMapping;
  21. import org.springframework.web.bind.annotation.RequestMapping;
  22. import org.springframework.web.bind.annotation.RestController;
  23. import com.alibaba.fastjson.JSONObject;
  24. import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
  25. import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  26. import org.springframework.web.context.request.async.DeferredResult;
  27. import java.util.UUID;
  28. import javax.sip.message.Response;
  29. @CrossOrigin
  30. @RestController
  31. @RequestMapping("/api")
  32. public class PlayController {
  33. private final static Logger logger = LoggerFactory.getLogger(PlayController.class);
  34. @Autowired
  35. private SIPCommander cmder;
  36. @Autowired
  37. private IVideoManagerStorager storager;
  38. @Autowired
  39. private IRedisCatchStorage redisCatchStorage;
  40. @Autowired
  41. private ZLMRESTfulUtils zlmresTfulUtils;
  42. @Autowired
  43. private DeferredResultHolder resultHolder;
  44. @Autowired
  45. private IPlayService playService;
  46. @Autowired
  47. private IMediaService mediaService;
  48. @GetMapping("/play/{deviceId}/{channelId}")
  49. public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId,
  50. @PathVariable String channelId) {
  51. PlayResult playResult = playService.play(deviceId, channelId, null, null);
  52. // 超时处理
  53. playResult.getResult().onTimeout(()->{
  54. logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId));
  55. // 释放rtpserver
  56. cmder.closeRTPServer(playResult.getDevice(), channelId);
  57. RequestMessage msg = new RequestMessage();
  58. msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + playResult.getUuid());
  59. msg.setData("Timeout");
  60. resultHolder.invokeResult(msg);
  61. });
  62. return playResult.getResult();
  63. }
  64. @PostMapping("/play/{streamId}/stop")
  65. public DeferredResult<ResponseEntity<String>> playStop(@PathVariable String streamId) {
  66. logger.debug(String.format("设备预览/回放停止API调用,streamId:%s", streamId));
  67. UUID uuid = UUID.randomUUID();
  68. DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>();
  69. // 录像查询以channelId作为deviceId查询
  70. resultHolder.put(DeferredResultHolder.CALLBACK_CMD_STOP + uuid, result);
  71. cmder.streamByeCmd(streamId, event -> {
  72. StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
  73. if (streamInfo == null) {
  74. RequestMessage msg = new RequestMessage();
  75. msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  76. msg.setData("streamId not found");
  77. resultHolder.invokeResult(msg);
  78. }else {
  79. redisCatchStorage.stopPlay(streamInfo);
  80. storager.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
  81. RequestMessage msg = new RequestMessage();
  82. msg.setId(DeferredResultHolder.CALLBACK_CMD_STOP + uuid);
  83. //Response response = event.getResponse();
  84. msg.setData(String.format("success"));
  85. resultHolder.invokeResult(msg);
  86. }
  87. });
  88. if (streamId != null) {
  89. JSONObject json = new JSONObject();
  90. json.put("streamId", streamId);
  91. RequestMessage msg = new RequestMessage();
  92. msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  93. msg.setData(json.toString());
  94. resultHolder.invokeResult(msg);
  95. } else {
  96. logger.warn("设备预览/回放停止API调用失败!");
  97. RequestMessage msg = new RequestMessage();
  98. msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  99. msg.setData("streamId null");
  100. resultHolder.invokeResult(msg);
  101. }
  102. // 超时处理
  103. result.onTimeout(()->{
  104. logger.warn(String.format("设备预览/回放停止超时,streamId:%s ", streamId));
  105. RequestMessage msg = new RequestMessage();
  106. msg.setId(DeferredResultHolder.CALLBACK_CMD_STOP + uuid);
  107. msg.setData("Timeout");
  108. resultHolder.invokeResult(msg);
  109. });
  110. return result;
  111. }
  112. /**
  113. * 将不是h264的视频通过ffmpeg 转码为h264 + aac
  114. * @param streamId 流ID
  115. * @return
  116. */
  117. @PostMapping("/play/{streamId}/convert")
  118. public ResponseEntity<String> playConvert(@PathVariable String streamId) {
  119. StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
  120. if (streamInfo == null) {
  121. logger.warn("视频转码API调用失败!, 视频流已经停止!");
  122. return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK);
  123. }
  124. JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
  125. if (!rtpInfo.getBoolean("exist")) {
  126. logger.warn("视频转码API调用失败!, 视频流已停止推流!");
  127. return new ResponseEntity<String>("推流信息在流媒体中不存在, 视频流可能已停止推流", HttpStatus.OK);
  128. } else {
  129. MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
  130. String dstUrl = String.format("rtmp://%s:%s/convert/%s", "127.0.0.1", mediaInfo.getRtmpPort(),
  131. streamId );
  132. String srcUrl = String.format("rtsp://%s:%s/rtp/%s", "127.0.0.1", mediaInfo.getRtspPort(), streamId);
  133. JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(srcUrl, dstUrl, "1000000");
  134. System.out.println(jsonObject);
  135. JSONObject result = new JSONObject();
  136. if (jsonObject != null && jsonObject.getInteger("code") == 0) {
  137. result.put("code", 0);
  138. JSONObject data = jsonObject.getJSONObject("data");
  139. if (data != null) {
  140. result.put("key", data.getString("key"));
  141. // StreamInfo streamInfoResult = new StreamInfo();
  142. // streamInfoResult.setRtmp(dstUrl);
  143. // streamInfoResult.setRtsp(String.format("rtsp://%s:%s/convert/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
  144. // streamInfoResult.setStreamId(streamId);
  145. // streamInfoResult.setFlv(String.format("http://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  146. // streamInfoResult.setWs_flv(String.format("ws://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  147. // streamInfoResult.setHls(String.format("http://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  148. // streamInfoResult.setWs_hls(String.format("ws://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  149. // streamInfoResult.setFmp4(String.format("http://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  150. // streamInfoResult.setWs_fmp4(String.format("ws://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  151. // streamInfoResult.setTs(String.format("http://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  152. // streamInfoResult.setWs_ts(String.format("ws://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  153. StreamInfo streamInfoResult = mediaService.getStreamInfoByAppAndStream("convert", streamId);
  154. streamInfoResult.setStreamId(streamId);
  155. result.put("data", streamInfoResult);
  156. }
  157. }else {
  158. result.put("code", 1);
  159. result.put("msg", "cover fail");
  160. }
  161. return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
  162. }
  163. }
  164. /**
  165. * 结束转码
  166. * @param key
  167. * @return
  168. */
  169. @PostMapping("/play/convert/stop/{key}")
  170. public ResponseEntity<String> playConvertStop(@PathVariable String key) {
  171. JSONObject jsonObject = zlmresTfulUtils.delFFmpegSource(key);
  172. System.out.println(jsonObject);
  173. JSONObject result = new JSONObject();
  174. if (jsonObject != null && jsonObject.getInteger("code") == 0) {
  175. result.put("code", 0);
  176. JSONObject data = jsonObject.getJSONObject("data");
  177. if (data != null && data.getBoolean("flag")) {
  178. result.put("code", "0");
  179. result.put("msg", "success");
  180. }else {
  181. }
  182. }else {
  183. result.put("code", 1);
  184. result.put("msg", "delFFmpegSource fail");
  185. }
  186. return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
  187. }
  188. /**
  189. * 语音广播命令API接口
  190. *
  191. * @param deviceId
  192. */
  193. @GetMapping("/broadcast/{deviceId}")
  194. @PostMapping("/broadcast/{deviceId}")
  195. public DeferredResult<ResponseEntity<String>> broadcastApi(@PathVariable String deviceId) {
  196. if (logger.isDebugEnabled()) {
  197. logger.debug("语音广播API调用");
  198. }
  199. Device device = storager.queryVideoDevice(deviceId);
  200. cmder.audioBroadcastCmd(device, event -> {
  201. Response response = event.getResponse();
  202. RequestMessage msg = new RequestMessage();
  203. msg.setId(DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId);
  204. JSONObject json = new JSONObject();
  205. json.put("DeviceID", deviceId);
  206. json.put("CmdType", "Broadcast");
  207. json.put("Result", "Failed");
  208. json.put("Description", String.format("语音广播操作失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
  209. msg.setData(json);
  210. resultHolder.invokeResult(msg);
  211. });
  212. DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(3 * 1000L);
  213. result.onTimeout(() -> {
  214. logger.warn(String.format("语音广播操作超时, 设备未返回应答指令"));
  215. RequestMessage msg = new RequestMessage();
  216. msg.setId(DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId);
  217. JSONObject json = new JSONObject();
  218. json.put("DeviceID", deviceId);
  219. json.put("CmdType", "Broadcast");
  220. json.put("Result", "Failed");
  221. json.put("Error", "Timeout. Device did not response to broadcast command.");
  222. msg.setData(json);
  223. resultHolder.invokeResult(msg);
  224. });
  225. resultHolder.put(DeferredResultHolder.CALLBACK_CMD_BROADCAST + deviceId, result);
  226. return result;
  227. }
  228. }