21个文件已修改
10个文件已添加
5 文件已重命名
1个文件已删除
| | |
| | | |
| | | private String wanIp; |
| | | |
| | | private long updateTime; |
| | | |
| | | @JSONField(name = "hls.fileBufSize") |
| | | private String hlsFileBufSize; |
| | | |
| | |
| | | public void setWanIp(String wanIp) { |
| | | this.wanIp = wanIp; |
| | | } |
| | | |
| | | public long getUpdateTime() { |
| | | return updateTime; |
| | | } |
| | | |
| | | public void setUpdateTime(long updateTime) { |
| | | this.updateTime = updateTime; |
| | | } |
| | | } |
| | |
| | | package com.genersoft.iot.vmp.media.zlm;
|
| | |
|
| | | import java.util.List;
|
| | | import java.util.UUID;
|
| | |
|
| | | import com.alibaba.fastjson.JSON;
|
| | |
| | | }
|
| | |
|
| | | String streamId = json.getString("stream");
|
| | | String app = json.getString("app");
|
| | | StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
|
| | |
|
| | |
|
| | | if ("rtp".equals(app)){
|
| | | JSONObject ret = new JSONObject();
|
| | | ret.put("code", 0);
|
| | | ret.put("close", true);
|
| | |
|
| | | if (streamInfo != null) {
|
| | | if (redisCatchStorage.isChannelSendingRTP(streamInfo.getChannelId())) {
|
| | | ret.put("close", false);
|
| | |
| | | redisCatchStorage.stopPlayback(streamInfo);
|
| | | }
|
| | | return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
|
| | | }else {
|
| | | JSONObject ret = new JSONObject();
|
| | | ret.put("code", 0);
|
| | | ret.put("close", false);
|
| | | return new ResponseEntity<String>(ret.toString(),HttpStatus.OK);
|
| | | }
|
| | |
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | // String data = json.getString("data");
|
| | | // List<MediaServerConfig> mediaServerConfigs = JSON.parseArray(JSON.toJSONString(json), MediaServerConfig.class);
|
| | | // MediaServerConfig mediaServerConfig = mediaServerConfigs.get(0);
|
| | |
|
| | | List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_started);
|
| | | if (subscribes != null && subscribes.size() > 0) {
|
| | | for (ZLMHttpHookSubscribe.Event subscribe : subscribes) {
|
| | | subscribe.response(json);
|
| | | }
|
| | | }
|
| | |
|
| | | MediaServerConfig mediaServerConfig = JSON.toJavaObject(json, MediaServerConfig.class);
|
| | | mediaServerConfig.setWanIp(StringUtils.isEmpty(mediaWanIp)? mediaIp: mediaWanIp);
|
| | | mediaServerConfig.setLocalIP(mediaIp);
|
| | | redisCatchStorage.updateMediaInfo(mediaServerConfig);
|
| | |
|
| | | // 重新发起代理
|
| | |
|
| | | JSONObject ret = new JSONObject();
|
| | | ret.put("code", 0);
|
| | | ret.put("msg", "success");
|
| | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | |
| | |
| | | } |
| | | return event; |
| | | } |
| | | |
| | | public List<ZLMHttpHookSubscribe.Event> getSubscribes(HookType type) { |
| | | ZLMHttpHookSubscribe.Event event= null; |
| | | Map<JSONObject, Event> eventMap = allSubscribes.get(type); |
| | | if (eventMap == null) { |
| | | return null; |
| | | } |
| | | List<ZLMHttpHookSubscribe.Event> result = new ArrayList<>(); |
| | | for (JSONObject key : eventMap.keySet()) { |
| | | result.add(eventMap.get(key)); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | |
| | | } |
| | |
| | | |
| | | public void updateMediaList() { |
| | | JSONObject mediaList = zlmresTfulUtils.getMediaList(); |
| | | if (mediaList == null) return; |
| | | String dataStr = mediaList.getString("data"); |
| | | |
| | | Integer code = mediaList.getInteger("code"); |
| | |
| | | public JSONObject stopSendRtp(Map<String, Object> param) { |
| | | return sendPost("stopSendRtp",param); |
| | | } |
| | | |
| | | public JSONObject addStreamProxy(String app, String stream, String url, boolean enable_hls, boolean enable_mp4, String rtp_type) { |
| | | Map<String, Object> param = new HashMap<>(); |
| | | param.put("vhost", "__defaultVhost__"); |
| | | param.put("app", app); |
| | | param.put("stream", stream); |
| | | param.put("url", url); |
| | | param.put("enable_hls", enable_hls?1:0); |
| | | param.put("enable_mp4", enable_mp4?1:0); |
| | | param.put("rtp_type", rtp_type); |
| | | return sendPost("addStreamProxy",param); |
| | | } |
| | | |
| | | public JSONObject closeStreams(String app, String stream) { |
| | | Map<String, Object> param = new HashMap<>(); |
| | | param.put("vhost", "__defaultVhost__"); |
| | | param.put("app", app); |
| | | param.put("stream", stream); |
| | | param.put("force", 1); |
| | | return sendPost("close_streams",param); |
| | | } |
| | | } |
| | |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.genersoft.iot.vmp.conf.MediaServerConfig; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto; |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | //import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| | | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| | | import com.genersoft.iot.vmp.vmanager.service.IStreamProxyService; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | @Component |
| | |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(ZLMRunner.class); |
| | | |
| | | // @Autowired |
| | | // private IVideoManagerStorager storager; |
| | | @Autowired |
| | | private IVideoManagerStorager storager; |
| | | |
| | | @Autowired |
| | | private IRedisCatchStorage redisCatchStorage; |
| | |
| | | @Autowired |
| | | private ZLMMediaListManager zlmMediaListManager; |
| | | |
| | | @Autowired |
| | | private ZLMHttpHookSubscribe hookSubscribe; |
| | | |
| | | @Autowired |
| | | private IStreamProxyService streamProxyService; |
| | | |
| | | @Override |
| | | public void run(String... strings) throws Exception { |
| | | JSONObject subscribeKey = new JSONObject(); |
| | | // 订阅 zlm启动事件 |
| | | hookSubscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_server_started,subscribeKey,(response)->{ |
| | | MediaServerConfig mediaServerConfig = JSONObject.toJavaObject(response, MediaServerConfig.class); |
| | | zLmRunning(mediaServerConfig); |
| | | }); |
| | | |
| | | // 获取zlm信息 |
| | | logger.info("等待zlm接入..."); |
| | | MediaServerConfig mediaServerConfig = getMediaServerConfig(); |
| | | |
| | | if (mediaServerConfig != null) { |
| | | logger.info("zlm接入成功..."); |
| | | if (autoConfig) saveZLMConfig(); |
| | | mediaServerConfig = getMediaServerConfig(); |
| | | redisCatchStorage.updateMediaInfo(mediaServerConfig); |
| | | // 更新流列表 |
| | | zlmMediaListManager.updateMediaList(); |
| | | zLmRunning(mediaServerConfig); |
| | | } |
| | | } |
| | | |
| | |
| | | JSONArray data = responseJSON.getJSONArray("data"); |
| | | if (data != null && data.size() > 0) { |
| | | mediaServerConfig = JSON.parseObject(JSON.toJSONString(data.get(0)), MediaServerConfig.class); |
| | | mediaServerConfig.setLocalIP(mediaIp); |
| | | mediaServerConfig.setWanIp(StringUtils.isEmpty(mediaWanIp)? mediaIp: mediaWanIp); |
| | | |
| | | } |
| | | } else { |
| | | logger.error("getMediaServerConfig失败, 1s后重试"); |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * zlm 连接成功或者zlm重启后 |
| | | */ |
| | | private void zLmRunning(MediaServerConfig mediaServerConfig){ |
| | | logger.info("zlm接入成功..."); |
| | | if (autoConfig) saveZLMConfig(); |
| | | MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); |
| | | if (System.currentTimeMillis() - mediaInfo.getUpdateTime() < 50){ |
| | | logger.info("zlm刚刚更新,忽略这次更新"); |
| | | return; |
| | | } |
| | | mediaServerConfig.setLocalIP(mediaIp); |
| | | mediaServerConfig.setWanIp(StringUtils.isEmpty(mediaWanIp)? mediaIp: mediaWanIp); |
| | | redisCatchStorage.updateMediaInfo(mediaServerConfig); |
| | | // 更新流列表 |
| | | zlmMediaListManager.updateMediaList(); |
| | | // 恢复流代理 |
| | | List<StreamProxyDto> streamProxyListForEnable = storager.getStreamProxyListForEnable(true); |
| | | for (StreamProxyDto streamProxyDto : streamProxyListForEnable) { |
| | | logger.info("恢复流代理," + streamProxyDto.getApp() + "/" + streamProxyDto.getStream()); |
| | | streamProxyService.addStreamProxyToZlm(streamProxyDto); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.media.zlm.dto; |
| | | |
| | | public class StreamProxyDto { |
| | | private String type; |
| | | private String app; |
| | | private String stream; |
| | | private String url; |
| | | private String src_url; |
| | | private String dst_url; |
| | | private int timeout_ms; |
| | | private String ffmpeg_cmd_key; |
| | | private String rtp_type; |
| | | private boolean enable; |
| | | private boolean enable_hls; |
| | | private boolean enable_mp4; |
| | | |
| | | public String getType() { |
| | | return type; |
| | | } |
| | | |
| | | public void setType(String type) { |
| | | this.type = type; |
| | | } |
| | | |
| | | public String getApp() { |
| | | return app; |
| | | } |
| | | |
| | | public void setApp(String app) { |
| | | this.app = app; |
| | | } |
| | | |
| | | public String getStream() { |
| | | return stream; |
| | | } |
| | | |
| | | public void setStream(String stream) { |
| | | this.stream = stream; |
| | | } |
| | | |
| | | public String getUrl() { |
| | | return url; |
| | | } |
| | | |
| | | public void setUrl(String url) { |
| | | this.url = url; |
| | | } |
| | | |
| | | public String getSrc_url() { |
| | | return src_url; |
| | | } |
| | | |
| | | public void setSrc_url(String src_url) { |
| | | this.src_url = src_url; |
| | | } |
| | | |
| | | public String getDst_url() { |
| | | return dst_url; |
| | | } |
| | | |
| | | public void setDst_url(String dst_url) { |
| | | this.dst_url = dst_url; |
| | | } |
| | | |
| | | public int getTimeout_ms() { |
| | | return timeout_ms; |
| | | } |
| | | |
| | | public void setTimeout_ms(int timeout_ms) { |
| | | this.timeout_ms = timeout_ms; |
| | | } |
| | | |
| | | public String getFfmpeg_cmd_key() { |
| | | return ffmpeg_cmd_key; |
| | | } |
| | | |
| | | public void setFfmpeg_cmd_key(String ffmpeg_cmd_key) { |
| | | this.ffmpeg_cmd_key = ffmpeg_cmd_key; |
| | | } |
| | | |
| | | public String getRtp_type() { |
| | | return rtp_type; |
| | | } |
| | | |
| | | public void setRtp_type(String rtp_type) { |
| | | this.rtp_type = rtp_type; |
| | | } |
| | | |
| | | public boolean isEnable() { |
| | | return enable; |
| | | } |
| | | |
| | | public void setEnable(boolean enable) { |
| | | this.enable = enable; |
| | | } |
| | | |
| | | public boolean isEnable_hls() { |
| | | return enable_hls; |
| | | } |
| | | |
| | | public void setEnable_hls(boolean enable_hls) { |
| | | this.enable_hls = enable_hls; |
| | | } |
| | | |
| | | public boolean isEnable_mp4() { |
| | | return enable_mp4; |
| | | } |
| | | |
| | | public void setEnable_mp4(boolean enable_mp4) { |
| | | this.enable_mp4 = enable_mp4; |
| | | } |
| | | } |
| | |
| | | package com.genersoft.iot.vmp.storager; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.genersoft.iot.vmp.common.RealVideo; |
| | | import com.genersoft.iot.vmp.common.StreamInfo; |
| | | import com.genersoft.iot.vmp.conf.MediaServerConfig; |
| | |
| | | * 获取当前媒体流列表 |
| | | * @return List<RealVideo> |
| | | */ |
| | | List<Object> getMediaList(int start, int end); |
| | | JSONObject getMediaList(int start, int end); |
| | | } |
| | |
| | | import com.genersoft.iot.vmp.gb28181.bean.Device;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
|
| | | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto;
|
| | | import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce;
|
| | | import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
|
| | | import com.github.pagehelper.PageInfo;
|
| | |
| | | * @param deviceId
|
| | | */
|
| | | public int clearMobilePositionsByDeviceId(String deviceId);
|
| | |
|
| | | /**
|
| | | * 新增代理流
|
| | | * @param streamProxyDto
|
| | | * @return
|
| | | */
|
| | | public int addStreamProxy(StreamProxyDto streamProxyDto);
|
| | |
|
| | | /**
|
| | | * 更新代理流
|
| | | * @param streamProxyDto
|
| | | * @return
|
| | | */
|
| | | public int updateStreamProxy(StreamProxyDto streamProxyDto);
|
| | |
|
| | | /**
|
| | | * 移除代理流
|
| | | * @param app
|
| | | * @param stream
|
| | | * @return
|
| | | */
|
| | | public int deleteStreamProxy(String app, String stream);
|
| | |
|
| | | /**
|
| | | * 按照是否启用获取代理流
|
| | | * @param enable
|
| | | * @return
|
| | | */
|
| | | public List<StreamProxyDto> getStreamProxyListForEnable(boolean enable);
|
| | |
|
| | | /**
|
| | | * 按照是app和stream获取代理流
|
| | | * @param app
|
| | | * @param stream
|
| | | * @return
|
| | | */
|
| | | public StreamProxyDto queryStreamProxy(String app, String stream);
|
| | |
|
| | | /**
|
| | | * 获取代理流
|
| | | * @param page
|
| | | * @param count
|
| | | * @return
|
| | | */
|
| | | PageInfo<StreamProxyDto> queryStreamProxyList(Integer page, Integer count);
|
| | | }
|
New file |
| | |
| | | package com.genersoft.iot.vmp.storager.dao; |
| | | |
| | | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto; |
| | | import org.apache.ibatis.annotations.*; |
| | | import org.springframework.stereotype.Repository; |
| | | |
| | | import java.util.List; |
| | | |
| | | @Mapper |
| | | @Repository |
| | | public interface StreamProxyMapper { |
| | | |
| | | @Insert("INSERT INTO stream_proxy (type, app, stream, url, src_url, dst_url, " + |
| | | "timeout_ms, ffmpeg_cmd_key, rtp_type, enable_hls, enable_mp4, enable) VALUES" + |
| | | "('${type}','${app}', '${stream}', '${url}', '${src_url}', '${dst_url}', " + |
| | | "'${timeout_ms}', '${ffmpeg_cmd_key}', '${rtp_type}', ${enable_hls}, ${enable_mp4}, ${enable} )") |
| | | int add(StreamProxyDto streamProxyDto); |
| | | |
| | | @Update("UPDATE stream_proxy " + |
| | | "SET type=#{type}, " + |
| | | "app=#{app}," + |
| | | "stream=#{stream}," + |
| | | "url=#{url}, " + |
| | | "src_url=#{src_url}," + |
| | | "dst_url=#{dst_url}, " + |
| | | "timeout_ms=#{timeout_ms}, " + |
| | | "ffmpeg_cmd_key=#{ffmpeg_cmd_key}, " + |
| | | "rtp_type=#{rtp_type}, " + |
| | | "enable_hls=#{enable_hls}, " + |
| | | "enable=#{enable}, " + |
| | | "enable_mp4=#{enable_mp4} " + |
| | | "WHERE app=#{app} AND stream=#{stream}") |
| | | int update(StreamProxyDto streamProxyDto); |
| | | |
| | | @Delete("DELETE FROM stream_proxy WHERE app=#{app} AND stream=#{stream}") |
| | | int del(String app, String stream); |
| | | |
| | | @Select("SELECT * FROM stream_proxy") |
| | | List<StreamProxyDto> selectAll(); |
| | | |
| | | @Select("SELECT * FROM stream_proxy WHERE enable=${enable}") |
| | | List<StreamProxyDto> selectForEnable(boolean enable); |
| | | |
| | | @Select("SELECT * FROM stream_proxy WHERE app=#{app} AND stream=#{stream}") |
| | | StreamProxyDto selectOne(String app, String stream); |
| | | } |
| | |
| | | package com.genersoft.iot.vmp.storager.impl; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.genersoft.iot.vmp.common.RealVideo; |
| | | import com.genersoft.iot.vmp.common.StreamInfo; |
| | | import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| | |
| | | */ |
| | | @Override |
| | | public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) { |
| | | mediaServerConfig.setUpdateTime(System.currentTimeMillis()); |
| | | return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX,mediaServerConfig); |
| | | } |
| | | |
| | |
| | | * @return List<RealVideo> |
| | | */ |
| | | @Override |
| | | public List<Object> getMediaList(int start, int end) { |
| | | public JSONObject getMediaList(int start, int end) { |
| | | String key = VideoManagerConstants.MEDIA_STREAM_PREFIX; |
| | | Set<Object> realVideos = redis.ZRange(key, start, end); |
| | | return new ArrayList(realVideos); |
| | | JSONObject jsonObject = new JSONObject(); |
| | | jsonObject.put("list", new ArrayList(realVideos)); |
| | | jsonObject.put("total", redis.zSize(key)); |
| | | |
| | | return jsonObject; |
| | | } |
| | | } |
| | |
| | | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| | | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| | | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto; |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
| | | import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper; |
| | | import com.genersoft.iot.vmp.storager.dao.DeviceMapper; |
| | | import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper; |
| | | import com.genersoft.iot.vmp.storager.dao.PatformChannelMapper; |
| | | import com.genersoft.iot.vmp.storager.dao.*; |
| | | import com.genersoft.iot.vmp.vmanager.platform.bean.ChannelReduce; |
| | | import com.genersoft.iot.vmp.storager.dao.DeviceMobilePositionMapper; |
| | | import com.github.pagehelper.PageHelper; |
| | | import com.github.pagehelper.PageInfo; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | |
| | | @Autowired |
| | | private PatformChannelMapper patformChannelMapper; |
| | | |
| | | @Autowired |
| | | private StreamProxyMapper streamProxyMapper; |
| | | |
| | | |
| | | |
| | |
| | | |
| | | /** |
| | | * 添加Mobile Position设备移动位置 |
| | | * @param MobilePosition |
| | | * @param mobilePosition |
| | | */ |
| | | @Override |
| | | public synchronized boolean insertMobilePosition(MobilePosition mobilePosition) { |
| | |
| | | return deviceMobilePositionMapper.clearMobilePositionsByDeviceId(deviceId); |
| | | } |
| | | |
| | | /** |
| | | * 新增代理流 |
| | | * @param streamProxyDto |
| | | * @return |
| | | */ |
| | | @Override |
| | | public int addStreamProxy(StreamProxyDto streamProxyDto) { |
| | | return streamProxyMapper.add(streamProxyDto); |
| | | } |
| | | |
| | | /** |
| | | * 更新代理流 |
| | | * @param streamProxyDto |
| | | * @return |
| | | */ |
| | | @Override |
| | | public int updateStreamProxy(StreamProxyDto streamProxyDto) { |
| | | return streamProxyMapper.update(streamProxyDto); |
| | | } |
| | | |
| | | /** |
| | | * 移除代理流 |
| | | * @param id |
| | | * @return |
| | | */ |
| | | @Override |
| | | public int deleteStreamProxy(String app, String stream) { |
| | | return streamProxyMapper.del(app, stream); |
| | | } |
| | | |
| | | /** |
| | | * 根据是否启用获取代理流列表 |
| | | * @param enable |
| | | * @return |
| | | */ |
| | | @Override |
| | | public List<StreamProxyDto> getStreamProxyListForEnable(boolean enable) { |
| | | return streamProxyMapper.selectForEnable(enable); |
| | | } |
| | | |
| | | /** |
| | | * 分页查询代理流列表 |
| | | * @param page |
| | | * @param count |
| | | * @return |
| | | */ |
| | | @Override |
| | | public PageInfo<StreamProxyDto> queryStreamProxyList(Integer page, Integer count) { |
| | | PageHelper.startPage(page, count); |
| | | List<StreamProxyDto> all = streamProxyMapper.selectAll(); |
| | | return new PageInfo<>(all); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 按照是app和stream获取代理流 |
| | | * @param app |
| | | * @param stream |
| | | * @return |
| | | */ |
| | | @Override |
| | | public StreamProxyDto queryStreamProxy(String app, String stream){ |
| | | return streamProxyMapper.selectOne(app, stream); |
| | | } |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.vmanager.media; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.genersoft.iot.vmp.common.StreamInfo; |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | import com.genersoft.iot.vmp.vmanager.service.IMediaService; |
| | | import com.genersoft.iot.vmp.vmanager.service.IStreamProxyService; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Controller; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | |
| | | @Controller |
| | | @CrossOrigin |
| | | @RequestMapping(value = "/api/media") |
| | | public class MediaController { |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(MediaController.class); |
| | | |
| | | @Autowired |
| | | private IRedisCatchStorage redisCatchStorage; |
| | | |
| | | @Autowired |
| | | private IStreamProxyService streamProxyService; |
| | | |
| | | @Autowired |
| | | private IMediaService mediaService; |
| | | |
| | | |
| | | @RequestMapping(value = "/list") |
| | | @ResponseBody |
| | | public JSONObject list( @RequestParam(required = false)Integer page, |
| | | @RequestParam(required = false)Integer count, |
| | | @RequestParam(required = false)String q, |
| | | @RequestParam(required = false)Boolean online ){ |
| | | |
| | | JSONObject jsonObject = redisCatchStorage.getMediaList(page - 1, page - 1 + count); |
| | | return jsonObject; |
| | | } |
| | | |
| | | @RequestMapping(value = "/getStreamInfoByAppAndStream") |
| | | @ResponseBody |
| | | public StreamInfo getStreamInfoByAppAndStream(String app, String stream){ |
| | | return mediaService.getStreamInfoByAppAndStreamWithCheck(app, stream); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | |
| | | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult; |
| | | import com.genersoft.iot.vmp.vmanager.service.IMediaService; |
| | | import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | |
| | | |
| | | @Autowired |
| | | private IPlayService playService; |
| | | |
| | | @Autowired |
| | | private IMediaService mediaService; |
| | | |
| | | @GetMapping("/play/{deviceId}/{channelId}") |
| | | public DeferredResult<ResponseEntity<String>> play(@PathVariable String deviceId, |
| | |
| | | JSONObject data = jsonObject.getJSONObject("data"); |
| | | if (data != null) { |
| | | result.put("key", data.getString("key")); |
| | | StreamInfo streamInfoResult = new StreamInfo(); |
| | | streamInfoResult.setRtmp(dstUrl); |
| | | streamInfoResult.setRtsp(String.format("rtsp://%s:%s/convert/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId)); |
| | | // StreamInfo streamInfoResult = new StreamInfo(); |
| | | // streamInfoResult.setRtmp(dstUrl); |
| | | // streamInfoResult.setRtsp(String.format("rtsp://%s:%s/convert/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId)); |
| | | // streamInfoResult.setStreamId(streamId); |
| | | // streamInfoResult.setFlv(String.format("http://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | // streamInfoResult.setWs_flv(String.format("ws://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | // streamInfoResult.setHls(String.format("http://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | // streamInfoResult.setWs_hls(String.format("ws://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | // streamInfoResult.setFmp4(String.format("http://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | // streamInfoResult.setWs_fmp4(String.format("ws://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | // streamInfoResult.setTs(String.format("http://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | // streamInfoResult.setWs_ts(String.format("ws://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | StreamInfo streamInfoResult = mediaService.getStreamInfoByAppAndStream("convert", streamId); |
| | | streamInfoResult.setStreamId(streamId); |
| | | streamInfoResult.setFlv(String.format("http://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | streamInfoResult.setWs_flv(String.format("ws://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | streamInfoResult.setHls(String.format("http://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | streamInfoResult.setWs_hls(String.format("ws://%s:%s/convert/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | streamInfoResult.setFmp4(String.format("http://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | streamInfoResult.setWs_fmp4(String.format("ws://%s:%s/convert/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | streamInfoResult.setTs(String.format("http://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | streamInfoResult.setWs_ts(String.format("ws://%s:%s/convert/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId)); |
| | | result.put("data", streamInfoResult); |
| | | } |
| | | }else { |
New file |
| | |
| | | package com.genersoft.iot.vmp.vmanager.service; |
| | | |
| | | import com.genersoft.iot.vmp.common.StreamInfo; |
| | | |
| | | /** |
| | | * 媒体信息业务 |
| | | */ |
| | | public interface IMediaService { |
| | | |
| | | /** |
| | | * 根据应用名和流ID获取播放地址, 通过zlm接口检查是否存在 |
| | | * @param app |
| | | * @param stream |
| | | * @return |
| | | */ |
| | | StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream); |
| | | |
| | | /** |
| | | * 根据应用名和流ID获取播放地址, 只是地址拼接 |
| | | * @param app |
| | | * @param stream |
| | | * @return |
| | | */ |
| | | StreamInfo getStreamInfoByAppAndStream(String app, String stream); |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.vmanager.service; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto; |
| | | import com.genersoft.iot.vmp.vmanager.streamProxy.StreamProxyController; |
| | | import com.github.pagehelper.PageInfo; |
| | | |
| | | public interface IStreamProxyService { |
| | | |
| | | /** |
| | | * 保存视频代理 |
| | | * @param param |
| | | */ |
| | | void save(StreamProxyDto param); |
| | | |
| | | /** |
| | | * 添加视频代理到zlm |
| | | * @param param |
| | | * @return |
| | | */ |
| | | JSONObject addStreamProxyToZlm(StreamProxyDto param); |
| | | |
| | | /** |
| | | * 从zlm移除视频代理 |
| | | * @param param |
| | | * @return |
| | | */ |
| | | JSONObject removeStreamProxyFromZlm(StreamProxyDto param); |
| | | |
| | | /** |
| | | * 分页查询 |
| | | * @param page |
| | | * @param count |
| | | * @return |
| | | */ |
| | | PageInfo<StreamProxyDto> getAll(Integer page, Integer count); |
| | | |
| | | /** |
| | | * 删除视频代理 |
| | | * @param app |
| | | * @param stream |
| | | */ |
| | | void del(String app, String stream); |
| | | |
| | | /** |
| | | * 启用视频代理 |
| | | * @param app |
| | | * @param stream |
| | | * @return |
| | | */ |
| | | boolean start(String app, String stream); |
| | | |
| | | /** |
| | | * 停用用视频代理 |
| | | * @param app |
| | | * @param stream |
| | | * @return |
| | | */ |
| | | boolean stop(String app, String stream); |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.vmanager.service.impl; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.genersoft.iot.vmp.common.StreamInfo; |
| | | import com.genersoft.iot.vmp.conf.MediaServerConfig; |
| | | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| | | import com.genersoft.iot.vmp.vmanager.service.IMediaService; |
| | | import com.genersoft.iot.vmp.vmanager.service.IStreamProxyService; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | @Service |
| | | public class MediaServiceImpl implements IMediaService { |
| | | |
| | | @Autowired |
| | | private IRedisCatchStorage redisCatchStorage; |
| | | |
| | | @Autowired |
| | | private IVideoManagerStorager storager; |
| | | |
| | | @Autowired |
| | | private ZLMRESTfulUtils zlmresTfulUtils; |
| | | |
| | | @Override |
| | | public StreamInfo getStreamInfoByAppAndStream(String app, String stream) { |
| | | MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); |
| | | StreamInfo streamInfoResult = new StreamInfo(); |
| | | streamInfoResult.setRtmp(String.format("rtmp://%s:%s/%s/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), app, stream)); |
| | | streamInfoResult.setRtsp(String.format("rtsp://%s:%s/%s/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), app, stream)); |
| | | streamInfoResult.setFlv(String.format("http://%s:%s/%s/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); |
| | | streamInfoResult.setWs_flv(String.format("ws://%s:%s/%s/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); |
| | | streamInfoResult.setHls(String.format("http://%s:%s/%s/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); |
| | | streamInfoResult.setWs_hls(String.format("ws://%s:%s/%s/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); |
| | | streamInfoResult.setFmp4(String.format("http://%s:%s/%s/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); |
| | | streamInfoResult.setWs_fmp4(String.format("ws://%s:%s/%s/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); |
| | | streamInfoResult.setTs(String.format("http://%s:%s/%s/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); |
| | | streamInfoResult.setWs_ts(String.format("ws://%s:%s/%s/%s.live.ts", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), app, stream)); |
| | | return streamInfoResult; |
| | | } |
| | | |
| | | @Override |
| | | public StreamInfo getStreamInfoByAppAndStreamWithCheck(String app, String stream) { |
| | | StreamInfo streamInfo = null; |
| | | JSONObject mediaList = zlmresTfulUtils.getMediaList(app, stream); |
| | | if (mediaList != null) { |
| | | streamInfo = getStreamInfoByAppAndStream(app, stream); |
| | | } |
| | | return streamInfo; |
| | | } |
| | | } |
| | |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| | | import com.genersoft.iot.vmp.vmanager.play.bean.PlayResult; |
| | | import com.genersoft.iot.vmp.vmanager.service.IMediaService; |
| | | import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | |
| | | |
| | | @Autowired |
| | | private ZLMRESTfulUtils zlmresTfulUtils; |
| | | |
| | | @Autowired |
| | | private IMediaService mediaService; |
| | | |
| | | |
| | | @Override |
| | |
| | | |
| | | public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) { |
| | | String streamId = resonse.getString("id"); |
| | | StreamInfo streamInfo = new StreamInfo(); |
| | | StreamInfo streamInfo = mediaService.getStreamInfoByAppAndStream("rtp", streamId); |
| | | // StreamInfo streamInfo = new StreamInfo(); |
| | | streamInfo.setStreamId(streamId); |
| | | streamInfo.setDeviceID(deviceId); |
| | | streamInfo.setChannelId(channelId); |
| | | MediaServerConfig mediaServerConfig = redisCatchStorage.getMediaInfo(); |
| | | // MediaServerConfig mediaServerConfig = redisCatchStorage.getMediaInfo(); |
| | | |
| | | streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | streamInfo.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | |
| | | streamInfo.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | streamInfo.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | |
| | | streamInfo.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | streamInfo.setWs_hls(String.format("ws://%s:%s/rtp/%s/hls.m3u8", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | |
| | | streamInfo.setTs(String.format("http://%s:%s/rtp/%s.live.ts", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | streamInfo.setWs_ts(String.format("ws://%s:%s/rtp/%s.live.ts", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | |
| | | streamInfo.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaServerConfig.getWanIp(), mediaServerConfig.getRtmpPort(), streamId)); |
| | | streamInfo.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaServerConfig.getWanIp(), mediaServerConfig.getRtspPort(), streamId)); |
| | | // streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | // streamInfo.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | // |
| | | // streamInfo.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | // streamInfo.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | // |
| | | // streamInfo.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | // streamInfo.setWs_hls(String.format("ws://%s:%s/rtp/%s/hls.m3u8", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | // |
| | | // streamInfo.setTs(String.format("http://%s:%s/rtp/%s.live.ts", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | // streamInfo.setWs_ts(String.format("ws://%s:%s/rtp/%s.live.ts", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| | | // |
| | | // streamInfo.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaServerConfig.getWanIp(), mediaServerConfig.getRtmpPort(), streamId)); |
| | | // streamInfo.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaServerConfig.getWanIp(), mediaServerConfig.getRtspPort(), streamId)); |
| | | |
| | | return streamInfo; |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.vmanager.service.impl; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.genersoft.iot.vmp.conf.MediaServerConfig; |
| | | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| | | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto; |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| | | import com.genersoft.iot.vmp.storager.dao.StreamProxyMapper; |
| | | import com.genersoft.iot.vmp.vmanager.service.IStreamProxyService; |
| | | import com.genersoft.iot.vmp.vmanager.streamProxy.StreamProxyController; |
| | | import com.github.pagehelper.PageHelper; |
| | | import com.github.pagehelper.PageInfo; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 视频代理业务 |
| | | */ |
| | | @Service |
| | | public class StreamProxyServiceImpl implements IStreamProxyService { |
| | | |
| | | @Autowired |
| | | private IVideoManagerStorager videoManagerStorager; |
| | | |
| | | @Autowired |
| | | private IRedisCatchStorage redisCatchStorage; |
| | | |
| | | @Autowired |
| | | private ZLMRESTfulUtils zlmresTfulUtils; |
| | | |
| | | @Autowired |
| | | private StreamProxyMapper streamProxyMapper; |
| | | |
| | | |
| | | @Override |
| | | public void save(StreamProxyDto param) { |
| | | MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); |
| | | String dstUrl = String.format("rtmp://%s:%s/%s/%s", "127.0.0.1", mediaInfo.getRtmpPort(), param.getApp(), |
| | | param.getStream() ); |
| | | param.setDst_url(dstUrl); |
| | | // 更新 |
| | | if (videoManagerStorager.queryStreamProxy(param.getApp(), param.getStream()) != null) { |
| | | int result = videoManagerStorager.updateStreamProxy(param); |
| | | if (result > 0 && param.isEnable()) { |
| | | addStreamProxyToZlm(param); |
| | | } |
| | | }else { // 新增 |
| | | int result = videoManagerStorager.addStreamProxy(param); |
| | | if (result > 0 && param.isEnable()) { |
| | | addStreamProxyToZlm(param); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public JSONObject addStreamProxyToZlm(StreamProxyDto param) { |
| | | JSONObject result = null; |
| | | if ("default".equals(param.getType())){ |
| | | result = zlmresTfulUtils.addStreamProxy(param.getApp(), param.getStream(), param.getUrl(), |
| | | param.isEnable_hls(), param.isEnable_mp4(), param.getRtp_type()); |
| | | }else if ("ffmpeg".equals(param.getType())) { |
| | | result = zlmresTfulUtils.addFFmpegSource(param.getSrc_url(), param.getDst_url(), |
| | | param.getTimeout_ms() + ""); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public JSONObject removeStreamProxyFromZlm(StreamProxyDto param) { |
| | | JSONObject result = zlmresTfulUtils.closeStreams(param.getApp(), param.getStream()); |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public PageInfo<StreamProxyDto> getAll(Integer page, Integer count) { |
| | | return videoManagerStorager.queryStreamProxyList(page, count); |
| | | } |
| | | |
| | | @Override |
| | | public void del(String app, String stream) { |
| | | StreamProxyDto streamProxyDto = new StreamProxyDto(); |
| | | streamProxyDto.setApp(app); |
| | | streamProxyDto.setStream(stream); |
| | | JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyDto); |
| | | if (jsonObject.getInteger("code") == 0) { |
| | | videoManagerStorager.deleteStreamProxy(app, stream); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public boolean start(String app, String stream) { |
| | | boolean result = false; |
| | | StreamProxyDto streamProxyDto = videoManagerStorager.queryStreamProxy(app, stream); |
| | | if (!streamProxyDto.isEnable() && streamProxyDto != null) { |
| | | JSONObject jsonObject = addStreamProxyToZlm(streamProxyDto); |
| | | if (jsonObject.getInteger("code") == 0) { |
| | | result = true; |
| | | streamProxyDto.setEnable(true); |
| | | videoManagerStorager.updateStreamProxy(streamProxyDto); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public boolean stop(String app, String stream) { |
| | | boolean result = false; |
| | | StreamProxyDto streamProxyDto = videoManagerStorager.queryStreamProxy(app, stream); |
| | | if (streamProxyDto.isEnable() && streamProxyDto != null) { |
| | | JSONObject jsonObject = removeStreamProxyFromZlm(streamProxyDto); |
| | | if (jsonObject.getInteger("code") == 0) { |
| | | result = true; |
| | | streamProxyDto.setEnable(false); |
| | | videoManagerStorager.updateStreamProxy(streamProxyDto); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | } |
New file |
| | |
| | | package com.genersoft.iot.vmp.vmanager.streamProxy; |
| | | |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| | | import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyDto; |
| | | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| | | import com.genersoft.iot.vmp.vmanager.service.IStreamProxyService; |
| | | import com.github.pagehelper.PageInfo; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Controller; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | /** |
| | | * 拉流代理接口 |
| | | */ |
| | | @Controller |
| | | @CrossOrigin |
| | | @RequestMapping(value = "/api/proxy") |
| | | public class StreamProxyController { |
| | | |
| | | private final static Logger logger = LoggerFactory.getLogger(StreamProxyController.class); |
| | | |
| | | @Autowired |
| | | private IRedisCatchStorage redisCatchStorage; |
| | | |
| | | @Autowired |
| | | private IStreamProxyService streamProxyService; |
| | | |
| | | |
| | | @RequestMapping(value = "/list") |
| | | @ResponseBody |
| | | public PageInfo<StreamProxyDto> list(@RequestParam(required = false)Integer page, |
| | | @RequestParam(required = false)Integer count, |
| | | @RequestParam(required = false)String q, |
| | | @RequestParam(required = false)Boolean online ){ |
| | | |
| | | return streamProxyService.getAll(page, count); |
| | | } |
| | | |
| | | @RequestMapping(value = "/save") |
| | | @ResponseBody |
| | | public Object save(@RequestBody StreamProxyDto param){ |
| | | logger.info("添加代理: " + JSONObject.toJSONString(param)); |
| | | streamProxyService.save(param); |
| | | return "success"; |
| | | } |
| | | |
| | | @RequestMapping(value = "/del") |
| | | @ResponseBody |
| | | public Object del(String app, String stream){ |
| | | logger.info("移除代理: " + app + "/" + stream); |
| | | streamProxyService.del(app, stream); |
| | | return "success"; |
| | | } |
| | | |
| | | @RequestMapping(value = "/start") |
| | | @ResponseBody |
| | | public Object start(String app, String stream){ |
| | | logger.info("启用代理: " + app + "/" + stream); |
| | | boolean result = streamProxyService.start(app, stream); |
| | | return "success"; |
| | | } |
| | | |
| | | @RequestMapping(value = "/stop") |
| | | @ResponseBody |
| | | public Object stop(String app, String stream){ |
| | | logger.info("停用代理: " + app + "/" + stream); |
| | | boolean result = streamProxyService.stop(app, stream); |
| | | return "success"; |
| | | } |
| | | } |
| | |
| | | "clipboard": "^2.0.0" |
| | | } |
| | | }, |
| | | "vue-clipboards": { |
| | | "version": "1.3.0", |
| | | "resolved": "https://registry.npmjs.org/vue-clipboards/-/vue-clipboards-1.3.0.tgz", |
| | | "integrity": "sha512-VMDYHpLQH0EUmqfk9b5XMrkvSu/HjNsLW2EBR4OS6JZHcv/PxmWYdoTBPVlp5eYrhWy07La8nWpRwAh09Mgufw==", |
| | | "requires": { |
| | | "clipboard": "^1.7.1" |
| | | }, |
| | | "dependencies": { |
| | | "clipboard": { |
| | | "version": "1.7.1", |
| | | "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-1.7.1.tgz", |
| | | "integrity": "sha1-Ng1taUbpmnof7zleQrqStem1oWs=", |
| | | "requires": { |
| | | "good-listener": "^1.2.2", |
| | | "select": "^1.1.2", |
| | | "tiny-emitter": "^2.0.0" |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | "vue-cookies": { |
| | | "version": "1.7.4", |
| | | "resolved": "https://registry.npm.taobao.org/vue-cookies/download/vue-cookies-1.7.4.tgz?cache=0&sync_timestamp=1598941352058&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-cookies%2Fdownload%2Fvue-cookies-1.7.4.tgz", |
| | |
| | | "vue": "^2.6.11", |
| | | "vue-baidu-map": "^0.21.22", |
| | | "vue-clipboard2": "^0.3.1", |
| | | "vue-clipboards": "^1.3.0", |
| | | "vue-cookies": "^1.7.4", |
| | | "vue-router": "^3.1.6" |
| | | }, |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import platformEdit from './platformEdit.vue' |
| | | import platformEdit from './dialog/platformEdit.vue' |
| | | import uiHeader from './UiHeader.vue' |
| | | import chooseChannelDialog from './gb28181/chooseChannel.vue' |
| | | import chooseChannelDialog from './dialog/chooseChannel.vue' |
| | | export default { |
| | | name: 'app', |
| | | components: { |
| | |
| | | <template> |
| | | <div id="app"> |
| | | <div id="pushVideoList"> |
| | | <el-container> |
| | | <el-header> |
| | | <uiHeader></uiHeader> |
| | |
| | | <el-main> |
| | | <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;"> |
| | | <span style="font-size: 1rem; font-weight: bold;">推流列表</span> |
| | | <div style="position: absolute; right: 1rem; top: 0.3rem;"> |
| | | <el-button icon="el-icon-refresh-right" circle size="mini" :loading="getDeviceListLoading" @click="getDeviceList()"></el-button> |
| | | </div> |
| | | <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;"> |
| | | <el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addStreamProxy">添加代理</el-button> |
| | | </div> |
| | | <!-- <devicePlayer ref="devicePlayer"></devicePlayer> --> |
| | | <el-table :data="deviceList" border style="width: 100%" :height="winHeight"> |
| | | <el-table-column prop="schema" label="协议" width="180" align="center"> |
| | | <devicePlayer ref="devicePlayer"></devicePlayer> |
| | | <el-table :data="pushList" border style="width: 100%" :height="winHeight"> |
| | | <el-table-column prop="app" label="APP" width="180" align="center"> |
| | | </el-table-column> |
| | | <el-table-column prop="streamUrl" label="流地址" width="240" align="center"> |
| | | <el-table-column prop="stream" label="流ID" width="240" align="center"> |
| | | </el-table-column> |
| | | <el-table-column prop="online" label="在线人数" width="240" align="center"> |
| | | <el-table-column prop="totalReaderCount" label="在线人数" width="240" align="center"> |
| | | </el-table-column> |
| | | <el-table-column prop="startTime" label="开始时间" align="center"> |
| | | <el-table-column prop="createStamp" label="开始时间" align="center"> |
| | | </el-table-column> |
| | | |
| | | |
| | | <el-table-column label="操作" width="360" align="center" fixed="right"> |
| | | <template slot-scope="scope"> |
| | | <el-button size="mini" :ref="scope.row.deviceId + 'refbtn' " icon="el-icon-refresh" @click="refDevice(scope.row)">刷新</el-button> |
| | | <el-button-group> |
| | | <el-button size="mini" icon="el-icon-video-play" @click="sendDevicePush(scope.row)">播放</el-button> |
| | | <el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="!!scope.row.streamId" @click="stopDevicePush(scope.row)">停止</el-button> |
| | | <el-button size="mini" icon="el-icon-video-play" @click="playPuhsh(scope.row)">播放</el-button> |
| | | <el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="!!scope.row.streamId" @click="stopPuhsh(scope.row)">停止</el-button> |
| | | </el-button-group> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | layout="total, sizes, prev, pager, next" |
| | | :total="total"> |
| | | </el-pagination> |
| | | |
| | | <streamProxyEdit ref="streamProxyEdit" ></streamProxyEdit> |
| | | </el-main> |
| | | </el-container> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import streamProxyEdit from './dialog/StreamProxyEdit.vue' |
| | | import devicePlayer from './dialog/devicePlayer.vue' |
| | | import uiHeader from './UiHeader.vue' |
| | | export default { |
| | | name: 'app', |
| | | name: 'pushVideoList', |
| | | components: { |
| | | devicePlayer, |
| | | streamProxyEdit, |
| | | uiHeader |
| | | }, |
| | | data() { |
| | | return { |
| | | deviceList: [], //设备列表 |
| | | currentDevice: {}, //当前操作设备对象 |
| | | |
| | | videoComponentList: [], |
| | | pushList: [], //设备列表 |
| | | currentPusher: {}, //当前操作设备对象 |
| | | updateLooper: 0, //数据刷新轮训标志 |
| | | currentDeviceChannelsLenth:0, |
| | | winHeight: window.innerHeight - 200, |
| | |
| | | }; |
| | | }, |
| | | computed: { |
| | | getcurrentDeviceChannels: function() { |
| | | let data = this.currentDevice['channelMap']; |
| | | let channels = null; |
| | | if (data) { |
| | | channels = Object.keys(data).map(key => { |
| | | return data[key]; |
| | | }); |
| | | this.currentDeviceChannelsLenth = channels.length; |
| | | } |
| | | |
| | | console.log("数据:" + JSON.stringify(channels)); |
| | | return channels; |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.initData(); |
| | | this.updateLooper = setInterval(this.initData, 10000); |
| | | // this.updateLooper = setInterval(this.initData, 10000); |
| | | }, |
| | | destroyed() { |
| | | this.$destroy('videojs'); |
| | |
| | | }, |
| | | methods: { |
| | | initData: function() { |
| | | this.getDeviceList(); |
| | | this.getPushList(); |
| | | }, |
| | | currentChange: function(val){ |
| | | this.currentPage = val; |
| | | this.getDeviceList(); |
| | | this.getPushList(); |
| | | }, |
| | | handleSizeChange: function(val){ |
| | | this.count = val; |
| | | this.getDeviceList(); |
| | | this.getPushList(); |
| | | }, |
| | | getDeviceList: function() { |
| | | getPushList: function() { |
| | | let that = this; |
| | | this.getDeviceListLoading = true; |
| | | this.$axios.get(`/api/devices`,{ |
| | | this.$axios.get(`/api/media/list`,{ |
| | | params: { |
| | | page: that.currentPage, |
| | | count: that.count |
| | |
| | | console.log(res); |
| | | console.log(res.data.list); |
| | | that.total = res.data.total; |
| | | that.deviceList = res.data.list; |
| | | that.pushList = res.data.list; |
| | | that.getDeviceListLoading = false; |
| | | }) |
| | | .catch(function (error) { |
| | | console.log(error); |
| | | that.getDeviceListLoading = false; |
| | | }); |
| | | |
| | | }, |
| | | showChannelList: function(row) { |
| | | console.log(JSON.stringify(row)) |
| | | this.$router.push(`/channelList/${row.deviceId}/0/15/1`); |
| | | addStreamProxy: function(){ |
| | | console.log(2222) |
| | | this.$refs.streamProxyEdit.openDialog(null, this.initData) |
| | | }, |
| | | showDevicePosition: function(row) { |
| | | console.log(JSON.stringify(row)) |
| | | this.$router.push(`/devicePosition/${row.deviceId}/0/15/1`); |
| | | saveStreamProxy: function(){ |
| | | }, |
| | | |
| | | //gb28181平台对接 |
| | | //刷新设备信息 |
| | | refDevice: function(itemData) { |
| | | ///api/devices/{deviceId}/sync |
| | | console.log("刷新对应设备:" + itemData.deviceId); |
| | | var that = this; |
| | | that.$refs[itemData.deviceId + 'refbtn' ].loading = true; |
| | | this.$axios({ |
| | | method: 'post', |
| | | url: '/api/devices/' + itemData.deviceId + '/sync' |
| | | }).then(function(res) { |
| | | console.log("刷新设备结果:"+JSON.stringify(res)); |
| | | if (!res.data.deviceId) { |
| | | that.$message({ |
| | | showClose: true, |
| | | message: res.data, |
| | | type: 'error' |
| | | }); |
| | | }else{ |
| | | that.$message({ |
| | | showClose: true, |
| | | message: '请求成功', |
| | | type: 'success' |
| | | }); |
| | | } |
| | | that.initData() |
| | | that.$refs[itemData.deviceId + 'refbtn' ].loading = false; |
| | | }).catch(function(e) { |
| | | console.error(e) |
| | | that.$refs[itemData.deviceId + 'refbtn' ].loading = false; |
| | | });; |
| | | }, |
| | | //通知设备上传媒体流 |
| | | sendDevicePush: function(itemData) { |
| | | // let deviceId = this.currentDevice.deviceId; |
| | | // let channelId = itemData.channelId; |
| | | // console.log("通知设备推流1:" + deviceId + " : " + channelId); |
| | | // let that = this; |
| | | // this.$axios({ |
| | | // method: 'get', |
| | | // url: '/api/play/' + deviceId + '/' + channelId |
| | | // }).then(function(res) { |
| | | // let ssrc = res.data.ssrc; |
| | | // that.$refs.devicePlayer.play(ssrc,deviceId,channelId); |
| | | // }).catch(function(e) { |
| | | // }); |
| | | }, |
| | | transportChange: function (row) { |
| | | console.log(row); |
| | | console.log(`修改传输方式为 ${row.streamMode}:${row.deviceId} `); |
| | | playPuhsh: function(row){ |
| | | let that = this; |
| | | this.$axios({ |
| | | method: 'get', |
| | | url: '/api/devices/' + row.deviceId + '/transport/' + row.streamMode |
| | | }).then(function(res) { |
| | | |
| | | }).catch(function(e) { |
| | | this.getListLoading = true; |
| | | this.$axios.get(`/api/media/getStreamInfoByAppAndStream`,{ |
| | | params: { |
| | | app: row.app, |
| | | stream: row.stream |
| | | } |
| | | }) |
| | | .then(function (res) { |
| | | that.getListLoading = false; |
| | | that.$refs.devicePlayer.openDialog("streamPlay", null, null, { |
| | | streamInfo: res.data, |
| | | hasAudio: true |
| | | }); |
| | | }) |
| | | .catch(function (error) { |
| | | console.log(error); |
| | | that.getListLoading = false; |
| | | }); |
| | | }, |
| | | stopPuhsh: function(row){ |
| | | console.log(row) |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | <template> |
| | | <div id="streamProxyList"> |
| | | <el-container> |
| | | <el-header> |
| | | <uiHeader></uiHeader> |
| | | </el-header> |
| | | <el-main> |
| | | <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;"> |
| | | <span style="font-size: 1rem; font-weight: bold;">拉流代理列表</span> |
| | | </div> |
| | | <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;font-size: 14px;"> |
| | | <el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addStreamProxy">添加代理</el-button> |
| | | </div> |
| | | <devicePlayer ref="devicePlayer"></devicePlayer> |
| | | <el-table :data="streamProxyList" border style="width: 100%" :height="winHeight"> |
| | | <el-table-column prop="app" label="应用名" align="center" show-overflow-tooltip/> |
| | | <el-table-column prop="stream" label="流ID" align="center" show-overflow-tooltip/> |
| | | <el-table-column label="流地址" width="400" align="center" show-overflow-tooltip > |
| | | <template slot-scope="scope"> |
| | | <div slot="reference" class="name-wrapper"> |
| | | |
| | | <el-tag size="medium" v-if="scope.row.type == 'default'"> |
| | | <i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="scope.row.url" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i> |
| | | {{scope.row.url}} |
| | | </el-tag> |
| | | <el-tag size="medium" v-if="scope.row.type != 'default'"> |
| | | <i class="cpoy-btn el-icon-document-copy" title="点击拷贝" v-clipboard="scope.row.src_url" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></i> |
| | | {{scope.row.src_url}} |
| | | </el-tag> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column label="转HLS" width="120" align="center"> |
| | | <template slot-scope="scope"> |
| | | <div slot="reference" class="name-wrapper"> |
| | | <el-tag size="medium" v-if="scope.row.enable_hls">已启用</el-tag> |
| | | <el-tag size="medium" type="info" v-if="!scope.row.enable_hls">未启用</el-tag> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="MP4录制" width="120" align="center"> |
| | | <template slot-scope="scope"> |
| | | <div slot="reference" class="name-wrapper"> |
| | | <el-tag size="medium" v-if="scope.row.enable_mp4">已启用</el-tag> |
| | | <el-tag size="medium" type="info" v-if="!scope.row.enable_mp4">未启用</el-tag> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="启用" width="120" align="center"> |
| | | <template slot-scope="scope"> |
| | | <div slot="reference" class="name-wrapper"> |
| | | <el-tag size="medium" v-if="scope.row.enable">已启用</el-tag> |
| | | <el-tag size="medium" type="info" v-if="!scope.row.enable">未启用</el-tag> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | |
| | | <el-table-column label="操作" width="360" align="center" fixed="right"> |
| | | <template slot-scope="scope"> |
| | | <el-button-group> |
| | | <el-button size="mini" icon="el-icon-video-play" v-if="scope.row.enable" @click="play(scope.row)">播放</el-button> |
| | | <el-button size="mini" icon="el-icon-close" type="success" v-if="scope.row.enable" @click="stop(scope.row)">停用</el-button> |
| | | <el-button size="mini" icon="el-icon-check" type="primary" v-if="!scope.row.enable" @click="start(scope.row)">启用</el-button> |
| | | <el-button size="mini" icon="el-icon-delete" type="danger" @click="deleteStreamProxy(scope.row)">删除</el-button> |
| | | </el-button-group> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <el-pagination |
| | | style="float: right" |
| | | @size-change="handleSizeChange" |
| | | @current-change="currentChange" |
| | | :current-page="currentPage" |
| | | :page-size="count" |
| | | :page-sizes="[15, 25, 35, 50]" |
| | | layout="total, sizes, prev, pager, next" |
| | | :total="total"> |
| | | </el-pagination> |
| | | <streamProxyEdit ref="streamProxyEdit" ></streamProxyEdit> |
| | | </el-main> |
| | | </el-container> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import streamProxyEdit from './dialog/StreamProxyEdit.vue' |
| | | import devicePlayer from './dialog/devicePlayer.vue' |
| | | import uiHeader from './UiHeader.vue' |
| | | export default { |
| | | name: 'streamProxyList', |
| | | components: { |
| | | devicePlayer, |
| | | streamProxyEdit, |
| | | uiHeader |
| | | }, |
| | | data() { |
| | | return { |
| | | streamProxyList: [], |
| | | currentPusher: {}, //当前操作设备对象 |
| | | updateLooper: 0, //数据刷新轮训标志 |
| | | currentDeviceChannelsLenth:0, |
| | | winHeight: window.innerHeight - 200, |
| | | currentPage:1, |
| | | count:15, |
| | | total:0, |
| | | getListLoading: false |
| | | }; |
| | | }, |
| | | computed: { |
| | | }, |
| | | mounted() { |
| | | this.initData(); |
| | | // this.updateLooper = setInterval(this.initData, 10000); |
| | | }, |
| | | destroyed() { |
| | | this.$destroy('videojs'); |
| | | clearTimeout(this.updateLooper); |
| | | }, |
| | | methods: { |
| | | initData: function() { |
| | | this.getStreamProxyList(); |
| | | }, |
| | | currentChange: function(val){ |
| | | this.currentPage = val; |
| | | this.getStreamProxyList(); |
| | | }, |
| | | handleSizeChange: function(val){ |
| | | this.count = val; |
| | | this.getStreamProxyList(); |
| | | }, |
| | | getStreamProxyList: function() { |
| | | let that = this; |
| | | this.getListLoading = true; |
| | | this.$axios.get(`/api/proxy/list`,{ |
| | | params: { |
| | | page: that.currentPage, |
| | | count: that.count |
| | | } |
| | | } ) |
| | | .then(function (res) { |
| | | console.log(res); |
| | | console.log(res.data.list); |
| | | that.total = res.data.total; |
| | | that.streamProxyList = res.data.list; |
| | | that.getListLoading = false; |
| | | }) |
| | | .catch(function (error) { |
| | | console.log(error); |
| | | that.getListLoading = false; |
| | | }); |
| | | }, |
| | | addStreamProxy: function(){ |
| | | this.$refs.streamProxyEdit.openDialog(null, this.initData) |
| | | }, |
| | | saveStreamProxy: function(){ |
| | | }, |
| | | play: function(row){ |
| | | let that = this; |
| | | this.getListLoading = true; |
| | | this.$axios.get(`/api/media/getStreamInfoByAppAndStream`,{ |
| | | params: { |
| | | app: row.app, |
| | | stream: row.stream |
| | | } |
| | | }) |
| | | .then(function (res) { |
| | | that.getListLoading = false; |
| | | that.$refs.devicePlayer.openDialog("streamPlay", null, null, { |
| | | streamInfo: res.data, |
| | | hasAudio: true |
| | | }); |
| | | }) |
| | | .catch(function (error) { |
| | | console.log(error); |
| | | that.getListLoading = false; |
| | | }); |
| | | |
| | | }, |
| | | deleteStreamProxy: function(row){ |
| | | console.log(1111) |
| | | let that = this; |
| | | this.getListLoading = true; |
| | | this.$axios.get(`/api/proxy/del`,{ |
| | | params: { |
| | | app: row.app, |
| | | stream: row.stream |
| | | } |
| | | }) |
| | | .then(function (res) { |
| | | that.getListLoading = false; |
| | | that.initData() |
| | | }) |
| | | .catch(function (error) { |
| | | console.log(error); |
| | | that.getListLoading = false; |
| | | }); |
| | | }, |
| | | start: function(row){ |
| | | let that = this; |
| | | this.getListLoading = true; |
| | | this.$axios.get(`/api/proxy/start`,{ |
| | | params: { |
| | | app: row.app, |
| | | stream: row.stream |
| | | } |
| | | }) |
| | | .then(function (res) { |
| | | that.getListLoading = false; |
| | | that.initData() |
| | | }) |
| | | .catch(function (error) { |
| | | console.log(error); |
| | | that.getListLoading = false; |
| | | }); |
| | | }, |
| | | stop: function(row){ |
| | | let that = this; |
| | | this.getListLoading = true; |
| | | this.$axios.get(`/api/proxy/stop`,{ |
| | | params: { |
| | | app: row.app, |
| | | stream: row.stream |
| | | } |
| | | }) |
| | | .then(function (res) { |
| | | that.getListLoading = false; |
| | | that.initData() |
| | | }) |
| | | .catch(function (error) { |
| | | console.log(error); |
| | | that.getListLoading = false; |
| | | }); |
| | | } |
| | | |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style> |
| | | .videoList { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | align-content: flex-start; |
| | | } |
| | | |
| | | .video-item { |
| | | position: relative; |
| | | width: 15rem; |
| | | height: 10rem; |
| | | margin-right: 1rem; |
| | | background-color: #000000; |
| | | } |
| | | |
| | | .video-item-img { |
| | | position: absolute; |
| | | top: 0; |
| | | bottom: 0; |
| | | left: 0; |
| | | right: 0; |
| | | margin: auto; |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .video-item-img:after { |
| | | content: ""; |
| | | display: inline-block; |
| | | position: absolute; |
| | | z-index: 2; |
| | | top: 0; |
| | | bottom: 0; |
| | | left: 0; |
| | | right: 0; |
| | | margin: auto; |
| | | width: 3rem; |
| | | height: 3rem; |
| | | background-image: url("../assets/loading.png"); |
| | | background-size: cover; |
| | | background-color: #000000; |
| | | } |
| | | |
| | | .video-item-title { |
| | | position: absolute; |
| | | bottom: 0; |
| | | color: #000000; |
| | | background-color: #ffffff; |
| | | line-height: 1.5rem; |
| | | padding: 0.3rem; |
| | | width: 14.4rem; |
| | | } |
| | | .cpoy-btn { |
| | | cursor: pointer; |
| | | margin-right: 10px; |
| | | } |
| | | </style> |
| | |
| | | <el-menu-item index="/">控制台</el-menu-item> |
| | | <el-menu-item index="/deviceList">设备列表</el-menu-item> |
| | | <el-menu-item index="/pushVideoList">推流列表</el-menu-item> |
| | | <el-menu-item index="/streamProxyList">拉流代理</el-menu-item> |
| | | <el-menu-item index="/parentPlatformList/15/1">国标级联</el-menu-item> |
| | | <el-switch v-model="alarmNotify" active-text="报警信息推送" style="display: block float: right" @change="sseControl"></el-switch> |
| | | <el-menu-item style="float: right;" @click="loginout">退出</el-menu-item> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import devicePlayer from './gb28181/devicePlayer.vue' |
| | | import devicePlayer from './dialog/devicePlayer.vue' |
| | | import uiHeader from './UiHeader.vue' |
| | | import moment from "moment"; |
| | | export default { |
New file |
| | |
| | | <template> |
| | | <div id="addStreamProxy" v-loading="isLoging"> |
| | | <el-dialog |
| | | title="添加代理" |
| | | width="40%" |
| | | top="2rem" |
| | | :close-on-click-modal="false" |
| | | :visible.sync="showDialog" |
| | | :destroy-on-close="true" |
| | | @close="close()" |
| | | > |
| | | <div id="shared" style="margin-top: 1rem;margin-right: 100px;"> |
| | | <el-form ref="streamProxy" :rules="rules" :model="proxyParam" label-width="140px"> |
| | | <el-form-item label="类型" prop="type"> |
| | | <el-select |
| | | v-model="proxyParam.type" |
| | | style="width: 100%" |
| | | placeholder="请选择代理类型" |
| | | > |
| | | <el-option label="默认" value="default"></el-option> |
| | | <el-option label="FFmpeg" value="ffmpeg"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="应用名" prop="app"> |
| | | <el-input v-model="proxyParam.app" clearable></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="流ID" prop="stream"> |
| | | <el-input v-model="proxyParam.stream" clearable></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="拉流地址" prop="url" v-if="proxyParam.type=='default'"> |
| | | <el-input v-model="proxyParam.url" clearable></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="拉流地址" prop="src_url" v-if="proxyParam.type=='ffmpeg'"> |
| | | <el-input v-model="proxyParam.src_url" clearable></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="超时时间" prop="timeout_ms" v-if="proxyParam.type=='ffmpeg'"> |
| | | <el-input v-model="proxyParam.timeout_ms" clearable></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="FFmpeg命令模板" prop="ffmpeg_cmd_key" v-if="proxyParam.type=='ffmpeg'"> |
| | | <el-input v-model="proxyParam.ffmpeg_cmd_key" clearable></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="拉流方式" prop="rtp_type" v-if="proxyParam.type=='default'"> |
| | | <el-select |
| | | v-model="proxyParam.rtp_type" |
| | | style="width: 100%" |
| | | placeholder="请选择拉流方式" |
| | | > |
| | | <el-option label="TCP" value="0"></el-option> |
| | | <el-option label="UDP" value="1"></el-option> |
| | | <el-option label="组播" value="2"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="其他选项"> |
| | | <div style="float: left;"> |
| | | <el-checkbox label="启用" v-model="proxyParam.enable" ></el-checkbox> |
| | | <el-checkbox label="转HLS" v-model="proxyParam.enable_hls" ></el-checkbox> |
| | | <el-checkbox label="MP4录制" v-model="proxyParam.enable_mp4" ></el-checkbox> |
| | | </div> |
| | | |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <div style="float: right;"> |
| | | <el-button type="primary" @click="onSubmit">{{onSubmit_text}}</el-button> |
| | | <el-button @click="close">取消</el-button> |
| | | </div> |
| | | |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "streamProxyEdit", |
| | | props: {}, |
| | | computed: {}, |
| | | created() {}, |
| | | data() { |
| | | // var deviceGBIdRules = async (rule, value, callback) => { |
| | | // console.log(value); |
| | | // if (value === "") { |
| | | // callback(new Error("请输入设备国标编号")); |
| | | // } else { |
| | | // var exit = await this.deviceGBIdExit(value); |
| | | // console.log(exit); |
| | | // console.log(exit == "true"); |
| | | // console.log(exit === "true"); |
| | | // if (exit) { |
| | | // callback(new Error("设备国标编号已存在")); |
| | | // } else { |
| | | // callback(); |
| | | // } |
| | | // } |
| | | // }; |
| | | return { |
| | | listChangeCallback: null, |
| | | showDialog: false, |
| | | isLoging: false, |
| | | onSubmit_text: "立即创建", |
| | | proxyParam: { |
| | | type: "default", |
| | | app: null, |
| | | stream: null, |
| | | url: "rtmp://58.200.131.2:1935/livetv/hunantv", |
| | | src_url: null, |
| | | timeout_ms: null, |
| | | ffmpeg_cmd_key: null, |
| | | rtp_type: null, |
| | | enable: true, |
| | | enable_hls: true, |
| | | enable_mp4: false, |
| | | }, |
| | | |
| | | rules: { |
| | | app: [{ required: true, message: "请输入应用名", trigger: "blur" }], |
| | | stream: [{ required: true, message: "请输入流ID", trigger: "blur" }], |
| | | url: [{ required: true, message: "请输入要代理的流", trigger: "blur" }], |
| | | src_url: [{ required: true, message: "请输入要代理的流", trigger: "blur" }], |
| | | timeout_ms: [{ required: true, message: "请输入FFmpeg推流成功超时时间", trigger: "blur" }], |
| | | ffmpeg_cmd_key: [{ required: false, message: "请输入FFmpeg命令参数模板(可选)", trigger: "blur" }], |
| | | }, |
| | | }; |
| | | }, |
| | | methods: { |
| | | openDialog: function (proxyParam, callback) { |
| | | this.showDialog = true; |
| | | this.listChangeCallback = callback; |
| | | if (proxyParam != null) { |
| | | this.proxyParam = proxyParam; |
| | | this.onSubmit_text = "保存"; |
| | | } else { |
| | | this.onSubmit_text = "立即创建"; |
| | | } |
| | | }, |
| | | onSubmit: function () { |
| | | console.log("onSubmit"); |
| | | var that = this; |
| | | that.$axios |
| | | .post(`/api/proxy/save`, that.proxyParam) |
| | | .then(function (res) { |
| | | console.log(res); |
| | | console.log(res.data == "success"); |
| | | if (res.data == "success") { |
| | | that.$message({ |
| | | showClose: true, |
| | | message: "保存成功", |
| | | type: "success", |
| | | }); |
| | | that.showDialog = false; |
| | | if (that.listChangeCallback != null) { |
| | | that.listChangeCallback(); |
| | | } |
| | | } |
| | | }) |
| | | .catch(function (error) { |
| | | console.log(error); |
| | | }); |
| | | }, |
| | | close: function () { |
| | | console.log("关闭添加视频平台"); |
| | | this.showDialog = false; |
| | | this.$refs.streamProxy.resetFields(); |
| | | }, |
| | | deviceGBIdExit: async function (deviceGbId) { |
| | | var result = false; |
| | | var that = this; |
| | | await that.$axios |
| | | .post(`/api/platforms/exit/${deviceGbId}`) |
| | | .then(function (res) { |
| | | result = res.data; |
| | | }) |
| | | .catch(function (error) { |
| | | console.log(error); |
| | | }); |
| | | return result; |
| | | }, |
| | | checkExpires: function() { |
| | | if (this.platform.enable && this.platform.expires == "0") { |
| | | this.platform.expires = "300"; |
| | | } |
| | | } |
| | | }, |
| | | }; |
| | | </script> |
File was renamed from web_src/src/components/gb28181/chooseChannel.vue |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import chooseChannelForGb from './chooseChannelForGb.vue' |
| | | import chooseChannelForGb from '../dialog/chooseChannelForGb.vue' |
| | | export default { |
| | | name: 'chooseChannel', |
| | | props: {}, |
File was renamed from web_src/src/components/gb28181/devicePlayer.vue |
| | |
| | | </div> |
| | | </el-tab-pane> |
| | | <!--{"code":0,"data":{"paths":["22-29-30.mp4"],"rootPath":"/home/kkkkk/Documents/ZLMediaKit/release/linux/Debug/www/record/hls/kkkkk/2020-05-11/"}}--> |
| | | <el-tab-pane label="录像查询" name="record"> |
| | | <el-tab-pane label="录像查询" name="record" v-if="showRrecord"> |
| | | <el-date-picker size="mini" v-model="videoHistory.date" type="date" value-format="yyyy-MM-dd" placeholder="日期" @change="queryRecords()"></el-date-picker> |
| | | <el-table :data="videoHistory.searchHistoryResult" height="150" v-loading="recordsLoading"> |
| | | <el-table-column label="名称" prop="name"></el-table-column> |
| | |
| | | </el-table> |
| | | </el-tab-pane> |
| | | <!--遥控界面--> |
| | | <el-tab-pane label="云台控制" name="control"> |
| | | <el-tab-pane label="云台控制" name="control" v-if="showPtz"> |
| | | <div style="display: flex; justify-content: left;"> |
| | | <div class="control-wrapper"> |
| | | <div class="control-btn control-top" @mousedown="ptzCamera(0, 2, 0)" @mouseup="ptzCamera(0, 0, 0)"> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import player from './player.vue' |
| | | import player from '../dialog/player.vue' |
| | | export default { |
| | | name: 'devicePlayer', |
| | | props: {}, |
| | |
| | | tracks: [], |
| | | coverPlaying:false, |
| | | tracksLoading: false, |
| | | recordPlay: "" |
| | | recordPlay: "", |
| | | showPtz: true, |
| | | showRrecord: true, |
| | | }; |
| | | }, |
| | | methods: { |
| | |
| | | this.videoHistory.date = param.date; |
| | | this.queryRecords() |
| | | break; |
| | | case "streamPlay": |
| | | this.showRrecord = false, |
| | | this.showPtz = false, |
| | | this.play(param.streamInfo, param.hasAudio) |
| | | break; |
| | | case "control": |
| | | break; |
| | | } |
| | |
| | | import VueClipboard from 'vue-clipboard2'; |
| | | import { Notification } from 'element-ui'; |
| | | import Fingerprint2 from 'fingerprintjs2'; |
| | | import VueClipboards from 'vue-clipboards'; |
| | | |
| | | |
| | | // 生成唯一ID |
| | | Fingerprint2.get(function(components) { |
| | |
| | | Vue.use(VueClipboard); |
| | | Vue.use(ElementUI); |
| | | Vue.use(VueCookies); |
| | | Vue.use(VueClipboards); |
| | | Vue.prototype.$axios = axios; |
| | | Vue.prototype.$notify = Notification; |
| | | |
| | |
| | | import deviceList from '../components/DeviceList.vue' |
| | | import channelList from '../components/channelList.vue' |
| | | import pushVideoList from '../components/PushVideoList.vue' |
| | | import streamProxyList from '../components/StreamProxyList.vue' |
| | | import devicePosition from '../components/devicePosition.vue' |
| | | import login from '../components/Login.vue' |
| | | import parentPlatformList from '../components/ParentPlatformList.vue' |
| | |
| | | component: pushVideoList, |
| | | }, |
| | | { |
| | | path: '/streamProxyList', |
| | | component: streamProxyList, |
| | | }, |
| | | { |
| | | path: '/login', |
| | | name: '登录', |
| | | component: login, |