panlinlin
4 years ago
37 changed files with 1418 additions and 218 deletions
@ -0,0 +1,112 @@ |
|||
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; |
|||
} |
|||
} |
@ -0,0 +1,46 @@ |
|||
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); |
|||
} |
@ -0,0 +1,52 @@ |
|||
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); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
} |
@ -0,0 +1,25 @@ |
|||
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); |
|||
} |
@ -0,0 +1,60 @@ |
|||
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); |
|||
} |
@ -0,0 +1,52 @@ |
|||
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; |
|||
} |
|||
} |
@ -0,0 +1,123 @@ |
|||
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; |
|||
} |
|||
} |
@ -0,0 +1,73 @@ |
|||
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"; |
|||
} |
|||
} |
@ -1,45 +0,0 @@ |
|||
package com.genersoft.iot.vmp.web; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.genersoft.iot.vmp.common.RealVideo; |
|||
import com.genersoft.iot.vmp.conf.SipConfig; |
|||
import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
|||
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.CrossOrigin; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.bind.annotation.ResponseBody; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 兼容LiveGBS的API:系统接口 |
|||
*/ |
|||
@Controller |
|||
@CrossOrigin |
|||
@RequestMapping(value = "/api/v1/media") |
|||
public class ApiMediaController { |
|||
|
|||
private final static Logger logger = LoggerFactory.getLogger(ApiMediaController.class); |
|||
|
|||
@Autowired |
|||
private IRedisCatchStorage redisCatchStorage; |
|||
|
|||
|
|||
@RequestMapping(value = "/list") |
|||
@ResponseBody |
|||
public JSONObject list( @RequestParam(required = false)Integer start, |
|||
@RequestParam(required = false)Integer limit, |
|||
@RequestParam(required = false)String q, |
|||
@RequestParam(required = false)Boolean online ){ |
|||
|
|||
List<Object> mediaList = redisCatchStorage.getMediaList(start - 1, start - 1 + limit); |
|||
JSONObject jsonObject = new JSONObject(); |
|||
jsonObject.put("code", 0); |
|||
jsonObject.put("data", mediaList); |
|||
return jsonObject; |
|||
} |
|||
} |
Binary file not shown.
@ -0,0 +1,297 @@ |
|||
<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> |
@ -0,0 +1,186 @@ |
|||
<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> |
Loading…
Reference in new issue