ApiStreamController.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. package com.genersoft.iot.vmp.web;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONArray;
  4. import com.alibaba.fastjson.JSONObject;
  5. import com.genersoft.iot.vmp.common.StreamInfo;
  6. import com.genersoft.iot.vmp.gb28181.bean.Device;
  7. import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  8. import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
  9. import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  10. import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  11. import com.genersoft.iot.vmp.vmanager.play.PlayController;
  12. import org.slf4j.Logger;
  13. import org.slf4j.LoggerFactory;
  14. import org.springframework.beans.factory.annotation.Autowired;
  15. import org.springframework.beans.factory.annotation.Value;
  16. import org.springframework.http.HttpStatus;
  17. import org.springframework.http.ResponseEntity;
  18. import org.springframework.web.bind.annotation.*;
  19. /**
  20. * 兼容LiveGBS的API:实时直播
  21. */
  22. @CrossOrigin
  23. @RestController
  24. @RequestMapping(value = "/api/v1/stream")
  25. public class ApiStreamController {
  26. private final static Logger logger = LoggerFactory.getLogger(ApiStreamController.class);
  27. @Autowired
  28. private SIPCommander cmder;
  29. @Autowired
  30. private IVideoManagerStorager storager;
  31. @Value("${media.closeWaitRTPInfo}")
  32. private boolean closeWaitRTPInfo;
  33. @Autowired
  34. private ZLMRESTfulUtils zlmresTfulUtils;
  35. /**
  36. * 实时直播 - 开始直播
  37. * @param serial 设备编号
  38. * @param channel 通道序号 默认值: 1
  39. * @param code 通道编号,通过 /api/v1/device/channellist 获取的 ChannelList.ID, 该参数和 channel 二选一传递即可
  40. * @param cdn TODO 转推 CDN 地址, 形如: [rtmp|rtsp]://xxx, encodeURIComponent
  41. * @param audio TODO 是否开启音频, 默认 开启
  42. * @param transport 流传输模式, 默认 UDP
  43. * @param checkchannelstatus TODO 是否检查通道状态, 默认 false, 表示 拉流前不检查通道状态是否在线
  44. * @param transportmode TODO 当 transport=TCP 时有效, 指示流传输主被动模式, 默认被动
  45. * @param timeout TODO 拉流超时(秒),
  46. * @return
  47. */
  48. @RequestMapping(value = "/start")
  49. private JSONObject start(String serial ,
  50. @RequestParam(required = false)Integer channel ,
  51. @RequestParam(required = false)String code,
  52. @RequestParam(required = false)String cdn,
  53. @RequestParam(required = false)String audio,
  54. @RequestParam(required = false)String transport,
  55. @RequestParam(required = false)String checkchannelstatus ,
  56. @RequestParam(required = false)String transportmode,
  57. @RequestParam(required = false)String timeout
  58. ){
  59. int getEncoding = closeWaitRTPInfo? 1: 0;
  60. Device device = storager.queryVideoDevice(serial);
  61. if (device == null ) {
  62. JSONObject result = new JSONObject();
  63. result.put("error","device[ " + serial + " ]未找到");
  64. return result;
  65. }else if (device.getOnline() == 0) {
  66. JSONObject result = new JSONObject();
  67. result.put("error","device[ " + code + " ]offline");
  68. return result;
  69. }
  70. DeviceChannel deviceChannel = storager.queryChannel(serial, code);
  71. if (deviceChannel == null) {
  72. JSONObject result = new JSONObject();
  73. result.put("error","channel[ " + code + " ]未找到");
  74. return result;
  75. }else if (deviceChannel.getStatus() == 0) {
  76. JSONObject result = new JSONObject();
  77. result.put("error","channel[ " + code + " ]offline");
  78. return result;
  79. }
  80. // 查询是否已经在播放
  81. StreamInfo streamInfo = storager.queryPlayByDevice(device.getDeviceId(), code);
  82. if (streamInfo == null) {
  83. logger.debug("streamInfo 等于null, 重新点播");
  84. streamInfo = cmder.playStreamCmd(device, code);
  85. }else {
  86. logger.debug("streamInfo 不等于null, 向流媒体查询是否正在推流");
  87. String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
  88. JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
  89. if (rtpInfo.getBoolean("exist")) {
  90. logger.debug("向流媒体查询正在推流, 直接返回: " + streamInfo.getRtsp());
  91. JSONObject result = new JSONObject();
  92. result.put("StreamID", streamInfo.getSsrc());
  93. result.put("DeviceID", device.getDeviceId());
  94. result.put("ChannelID", code);
  95. result.put("ChannelName", deviceChannel.getName());
  96. result.put("ChannelCustomName ", "");
  97. result.put("FLV ", streamInfo.getFlv());
  98. result.put("WS_FLV ", streamInfo.getWs_flv());
  99. result.put("RTMP", streamInfo.getRtmp());
  100. result.put("HLS", streamInfo.getHls());
  101. result.put("RTSP", streamInfo.getRtsp());
  102. result.put("CDN", "");
  103. result.put("SnapURL", "");
  104. result.put("Transport", device.getTransport());
  105. result.put("StartAt", "");
  106. result.put("Duration", "");
  107. result.put("SourceVideoCodecName", "");
  108. result.put("SourceVideoWidth", "");
  109. result.put("SourceVideoHeight", "");
  110. result.put("SourceVideoFrameRate", "");
  111. result.put("SourceAudioCodecName", "");
  112. result.put("SourceAudioSampleRate", "");
  113. result.put("AudioEnable", "");
  114. result.put("Ondemand", "");
  115. result.put("InBytes", "");
  116. result.put("InBitRate", "");
  117. result.put("OutBytes", "");
  118. result.put("NumOutputs", "");
  119. result.put("CascadeSize", "");
  120. result.put("RelaySize", "");
  121. result.put("ChannelPTZType", 0);
  122. return result;
  123. } else {
  124. logger.debug("向流媒体查询没有推流, 重新点播");
  125. storager.stopPlay(streamInfo);
  126. streamInfo = cmder.playStreamCmd(device, code);
  127. }
  128. }
  129. if (logger.isDebugEnabled()) {
  130. logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",serial, code));
  131. logger.debug("设备预览 API调用,ssrc:"+streamInfo.getSsrc()+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(streamInfo.getSsrc())));
  132. }
  133. boolean lockFlag = true;
  134. long startTime = System.currentTimeMillis();
  135. while (lockFlag) {
  136. try {
  137. if (System.currentTimeMillis() - startTime > 10 * 1000) {
  138. storager.stopPlay(streamInfo);
  139. logger.info("播放等待超时");
  140. JSONObject result = new JSONObject();
  141. result.put("error","timeout");
  142. return result;
  143. } else {
  144. StreamInfo streamInfoNow = storager.queryPlayByDevice(serial, code);
  145. logger.debug("正在向流媒体查询");
  146. if (streamInfoNow != null && streamInfoNow.getFlv() != null) {
  147. streamInfo = streamInfoNow;
  148. logger.debug("向流媒体查询到: " + streamInfoNow.getRtsp());
  149. lockFlag = false;
  150. continue;
  151. } else {
  152. Thread.sleep(2000);
  153. continue;
  154. }
  155. }
  156. } catch (InterruptedException e) {
  157. e.printStackTrace();
  158. }
  159. }
  160. if(streamInfo!=null) {
  161. JSONObject result = new JSONObject();
  162. result.put("StreamID", streamInfo.getSsrc());
  163. result.put("DeviceID", device.getDeviceId());
  164. result.put("ChannelID", code);
  165. result.put("ChannelName", deviceChannel.getName());
  166. result.put("ChannelCustomName ", "");
  167. result.put("FLV ", streamInfo.getFlv());
  168. result.put("WS_FLV ", streamInfo.getWs_flv());
  169. result.put("RTMP", streamInfo.getRtmp());
  170. result.put("HLS", streamInfo.getHls());
  171. result.put("RTSP", streamInfo.getRtsp());
  172. result.put("CDN", "");
  173. result.put("SnapURL", "");
  174. result.put("Transport", device.getTransport());
  175. result.put("StartAt", "");
  176. result.put("Duration", "");
  177. result.put("SourceVideoCodecName", "");
  178. result.put("SourceVideoWidth", "");
  179. result.put("SourceVideoHeight", "");
  180. result.put("SourceVideoFrameRate", "");
  181. result.put("SourceAudioCodecName", "");
  182. result.put("SourceAudioSampleRate", "");
  183. result.put("AudioEnable", "");
  184. result.put("Ondemand", "");
  185. result.put("InBytes", "");
  186. result.put("InBitRate", "");
  187. result.put("OutBytes", "");
  188. result.put("NumOutputs", "");
  189. result.put("CascadeSize", "");
  190. result.put("RelaySize", "");
  191. result.put("ChannelPTZType", 0);
  192. return result;
  193. } else {
  194. logger.warn("设备预览API调用失败!");
  195. JSONObject result = new JSONObject();
  196. result.put("error","调用失败");
  197. return result;
  198. }
  199. }
  200. /**
  201. * 实时直播 - 直播流停止
  202. * @param serial 设备编号
  203. * @param channel 通道序号
  204. * @param code 通道国标编号
  205. * @param check_outputs
  206. * @return
  207. */
  208. @RequestMapping(value = "/stop")
  209. @ResponseBody
  210. private JSONObject stop(String serial ,
  211. @RequestParam(required = false)Integer channel ,
  212. @RequestParam(required = false)String code,
  213. @RequestParam(required = false)String check_outputs
  214. ){
  215. StreamInfo streamInfo = storager.queryPlayByDevice(serial, code);
  216. if (streamInfo == null) {
  217. JSONObject result = new JSONObject();
  218. result.put("error","未找到流信息");
  219. return result;
  220. }
  221. cmder.streamByeCmd(streamInfo.getSsrc());
  222. storager.stopPlay(streamInfo);
  223. return null;
  224. }
  225. /**
  226. * 实时直播 - 直播流保活
  227. * @param serial 设备编号
  228. * @param channel 通道序号
  229. * @param code 通道国标编号
  230. * @return
  231. */
  232. @RequestMapping(value = "/touch")
  233. @ResponseBody
  234. private JSONObject touch(String serial ,String t,
  235. @RequestParam(required = false)Integer channel ,
  236. @RequestParam(required = false)String code,
  237. @RequestParam(required = false)String autorestart,
  238. @RequestParam(required = false)String audio,
  239. @RequestParam(required = false)String cdn
  240. ){
  241. return null;
  242. }
  243. }