PlayController.java 10 KB

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