Commit 09470bef96d48373219ac03315a4391c24accf98

Authored by 648540858
1 parent 4e9c6b2f

添加网页自动转码,以支持h265 g.711的播放

src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -128,29 +128,29 @@ public class ZLMHttpHookListener { @@ -128,29 +128,29 @@ public class ZLMHttpHookListener {
128 } 128 }
129 String app = json.getString("app"); 129 String app = json.getString("app");
130 String streamId = json.getString("id"); 130 String streamId = json.getString("id");
  131 + if ("rtp".equals(app)) {
  132 + String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
  133 + StreamInfo streamInfoForPlay = storager.queryPlayBySSRC(ssrc);
  134 + if ("rtp".equals(app) && streamInfoForPlay != null ) {
  135 + MediaServerConfig mediaInfo = storager.getMediaInfo();
  136 + streamInfoForPlay.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  137 + streamInfoForPlay.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  138 + streamInfoForPlay.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
  139 + streamInfoForPlay.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  140 + streamInfoForPlay.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
  141 + storager.startPlay(streamInfoForPlay);
  142 + }
131 143
132 -  
133 - String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));  
134 - StreamInfo streamInfoForPlay = storager.queryPlayBySSRC(ssrc);  
135 - if ("rtp".equals(app) && streamInfoForPlay != null ) {  
136 - MediaServerConfig mediaInfo = storager.getMediaInfo();  
137 - streamInfoForPlay.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));  
138 - streamInfoForPlay.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));  
139 - streamInfoForPlay.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));  
140 - streamInfoForPlay.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));  
141 - streamInfoForPlay.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));  
142 - storager.startPlay(streamInfoForPlay);  
143 - }  
144 -  
145 - StreamInfo streamInfoForPlayBack = storager.queryPlaybackBySSRC(ssrc);  
146 - if ("rtp".equals(app) && streamInfoForPlayBack != null ) {  
147 - MediaServerConfig mediaInfo = storager.getMediaInfo();  
148 - streamInfoForPlayBack.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));  
149 - streamInfoForPlayBack.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));  
150 - streamInfoForPlayBack.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));  
151 - streamInfoForPlayBack.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));  
152 - streamInfoForPlayBack.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));  
153 - storager.startPlayback(streamInfoForPlayBack); 144 + StreamInfo streamInfoForPlayBack = storager.queryPlaybackBySSRC(ssrc);
  145 + if ("rtp".equals(app) && streamInfoForPlayBack != null ) {
  146 + MediaServerConfig mediaInfo = storager.getMediaInfo();
  147 + streamInfoForPlayBack.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  148 + streamInfoForPlayBack.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  149 + streamInfoForPlayBack.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
  150 + streamInfoForPlayBack.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  151 + streamInfoForPlayBack.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
  152 + storager.startPlayback(streamInfoForPlayBack);
  153 + }
154 } 154 }
155 155
156 // TODO Auto-generated method stub 156 // TODO Auto-generated method stub
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
@@ -89,6 +89,22 @@ public class ZLMRESTfulUtils { @@ -89,6 +89,22 @@ public class ZLMRESTfulUtils {
89 return sendPost("getRtpInfo",param); 89 return sendPost("getRtpInfo",param);
90 } 90 }
91 91
  92 + public JSONObject addFFmpegSource(String src_url, String dst_url, String timeout_ms){
  93 + System.out.println(src_url);
  94 + System.out.println(dst_url);
  95 + Map<String, Object> param = new HashMap<>();
  96 + param.put("src_url", src_url);
  97 + param.put("dst_url", dst_url);
  98 + param.put("timeout_ms", timeout_ms);
  99 + return sendPost("addFFmpegSource",param);
  100 + }
  101 +
  102 + public JSONObject delFFmpegSource(String key){
  103 + Map<String, Object> param = new HashMap<>();
  104 + param.put("key", key);
  105 + return sendPost("delFFmpegSource",param);
  106 + }
  107 +
92 public JSONObject getMediaServerConfig(){ 108 public JSONObject getMediaServerConfig(){
93 return sendPost("getServerConfig",null); 109 return sendPost("getServerConfig",null);
94 } 110 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
@@ -101,7 +101,8 @@ public class ZLMRunner implements CommandLineRunner { @@ -101,7 +101,8 @@ public class ZLMRunner implements CommandLineRunner {
101 101
102 String hookPrex = String.format("http://%s:%s/index/hook", hookIP, serverPort); 102 String hookPrex = String.format("http://%s:%s/index/hook", hookIP, serverPort);
103 Map<String, Object> param = new HashMap<>(); 103 Map<String, Object> param = new HashMap<>();
104 - param.put("secret",mediaSecret); 104 + param.put("api.secret",mediaSecret); // -profile:v Baseline
  105 + param.put("ffmpeg.cmd","%s -fflags nobuffer -rtsp_transport tcp -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s");
105 param.put("hook.enable","1"); 106 param.put("hook.enable","1");
106 param.put("hook.on_flow_report",""); 107 param.put("hook.on_flow_report","");
107 param.put("hook.on_play",""); 108 param.put("hook.on_play","");
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java
@@ -29,7 +29,7 @@ public class ZLMUtils { @@ -29,7 +29,7 @@ public class ZLMUtils {
29 param.put("enable_tcp", 1); 29 param.put("enable_tcp", 1);
30 param.put("stream_id", streamId); 30 param.put("stream_id", streamId);
31 JSONObject jsonObject = zlmresTfulUtils.openRtpServer(param); 31 JSONObject jsonObject = zlmresTfulUtils.openRtpServer(param);
32 - if (jsonObject.getInteger("code") == 0) { 32 + if (jsonObject != null && jsonObject.getInteger("code") == 0) {
33 return newPort; 33 return newPort;
34 } else { 34 } else {
35 return getNewRTPPort(ssrc); 35 return getNewRTPPort(ssrc);
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
@@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.vmanager.play; @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.vmanager.play;
3 import com.alibaba.fastjson.JSON; 3 import com.alibaba.fastjson.JSON;
4 import com.alibaba.fastjson.JSONArray; 4 import com.alibaba.fastjson.JSONArray;
5 import com.genersoft.iot.vmp.common.StreamInfo; 5 import com.genersoft.iot.vmp.common.StreamInfo;
  6 +import com.genersoft.iot.vmp.conf.MediaServerConfig;
6 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; 7 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
7 import org.slf4j.Logger; 8 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory; 9 import org.slf4j.LoggerFactory;
@@ -46,7 +47,7 @@ public class PlayController { @@ -46,7 +47,7 @@ public class PlayController {
46 Integer getEncoding) { 47 Integer getEncoding) {
47 48
48 if (getEncoding == null) getEncoding = 0; 49 if (getEncoding == null) getEncoding = 0;
49 - getEncoding = closeWaitRTPInfo ? 0: getEncoding; 50 + getEncoding = closeWaitRTPInfo ? 0 : getEncoding;
50 Device device = storager.queryVideoDevice(deviceId); 51 Device device = storager.queryVideoDevice(deviceId);
51 StreamInfo streamInfo = storager.queryPlayByDevice(deviceId, channelId); 52 StreamInfo streamInfo = storager.queryPlayByDevice(deviceId, channelId);
52 53
@@ -149,5 +150,73 @@ public class PlayController { @@ -149,5 +150,73 @@ public class PlayController {
149 return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR); 150 return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
150 } 151 }
151 } 152 }
  153 +
  154 + /**
  155 + * 将不是h264的视频通过ffmpeg 转码为h264 + aac
  156 + * @param ssrc
  157 + * @return
  158 + */
  159 + @PostMapping("/play/{ssrc}/convert")
  160 + public ResponseEntity<String> playConvert(@PathVariable String ssrc) {
  161 + StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
  162 + if (streamInfo == null) {
  163 + logger.warn("视频转码API调用失败!, 视频流已经停止!");
  164 + return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK);
  165 + }
  166 + String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
  167 + JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
  168 + if (!rtpInfo.getBoolean("exist")) {
  169 + logger.warn("视频转码API调用失败!, 视频流已停止推流!");
  170 + return new ResponseEntity<String>("推流信息在流媒体中不存在, 视频流可能已停止推流", HttpStatus.OK);
  171 + } else {
  172 + MediaServerConfig mediaInfo = storager.getMediaInfo();
  173 + String dstUrl = String.format("rtmp://%s:%s/convert/%s", "127.0.0.1", mediaInfo.getRtmpPort(),
  174 + streamId );
  175 + JSONObject jsonObject = zlmresTfulUtils.addFFmpegSource(streamInfo.getRtsp(), dstUrl, "1000000");
  176 + System.out.println(jsonObject);
  177 + JSONObject result = new JSONObject();
  178 + if (jsonObject != null && jsonObject.getInteger("code") == 0) {
  179 + result.put("code", 0);
  180 + JSONObject data = jsonObject.getJSONObject("data");
  181 + if (data != null) {
  182 + result.put("key", data.getString("key"));
  183 + result.put("rtmp", dstUrl);
  184 + result.put("flv", String.format("http://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  185 + result.put("ws_flv", String.format("ws://%s:%s/convert/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
  186 + }
  187 + }else {
  188 + result.put("code", 1);
  189 + result.put("msg", "cover fail");
  190 + }
  191 + return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
  192 + }
  193 + }
  194 +
  195 + /**
  196 + * 结束转码
  197 + * @param key
  198 + * @return
  199 + */
  200 + @PostMapping("/play/convert/stop/{key}")
  201 + public ResponseEntity<String> playConvertStop(@PathVariable String key) {
  202 +
  203 + JSONObject jsonObject = zlmresTfulUtils.delFFmpegSource(key);
  204 + System.out.println(jsonObject);
  205 + JSONObject result = new JSONObject();
  206 + if (jsonObject != null && jsonObject.getInteger("code") == 0) {
  207 + result.put("code", 0);
  208 + JSONObject data = jsonObject.getJSONObject("data");
  209 + if (data != null && data.getBoolean("flag")) {
  210 + result.put("code", "0");
  211 + result.put("msg", "success");
  212 + }else {
  213 +
  214 + }
  215 + }else {
  216 + result.put("code", 1);
  217 + result.put("msg", "delFFmpegSource fail");
  218 + }
  219 + return new ResponseEntity<String>( result.toJSONString(), HttpStatus.OK);
  220 + }
152 } 221 }
153 222
src/main/resources/application.yml
@@ -44,8 +44,11 @@ media: #zlm服务器的ip与http端口, 重点: 这是http端口 @@ -44,8 +44,11 @@ media: #zlm服务器的ip与http端口, 重点: 这是http端口
44 wanIp: 44 wanIp:
45 port: 80 45 port: 80
46 secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc 46 secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
47 - streamNoneReaderDelayMS: 1800000 # 无人观看多久自动关闭流  
48 - closeWaitRTPInfo: false # 强制关闭等待收到流编码信息后在返回, 设为true可以快速打开播放窗口, 设为false保证返回后流就可以播放 47 + streamNoneReaderDelayMS: 600000 # 无人观看多久自动关闭流
  48 + # 关闭等待收到流编码信息后在返回,
  49 + # 设为false可以获得更好的兼容性,保证返回后流就可以播放,
  50 + # 设为true可以快速打开播放窗口,可以获得更好的体验
  51 + closeWaitRTPInfo: true
49 rtp: # 启用udp多端口模式 52 rtp: # 启用udp多端口模式
50 enable: true 53 enable: true
51 udpPortRange: 30000,30500 # 端口范围 54 udpPortRange: 30000,30500 # 端口范围
web_src/src/components/gb28181/devicePlayer.vue
1 <template> 1 <template>
2 -<div id="devicePlayer"> 2 +<div id="devicePlayer" v-loading="isLoging">
3 <el-dialog title="视频播放" top="0" :close-on-click-modal="false" :visible.sync="showVideoDialog" :destroy-on-close="true" @close="close()"> 3 <el-dialog title="视频播放" top="0" :close-on-click-modal="false" :visible.sync="showVideoDialog" :destroy-on-close="true" @close="close()">
4 - <LivePlayer v-if="showVideoDialog" ref="videoPlayer" :videoUrl="videoUrl" :error="videoError" :hasaudio="hasaudio" fluent autoplay live></LivePlayer> 4 + <LivePlayer v-if="showVideoDialog" ref="videoPlayer" :videoUrl="videoUrl" :error="videoError" :message="videoError" :hasaudio="hasaudio" fluent autoplay live></LivePlayer>
5 <div id="shared" style="text-align: right; margin-top: 1rem;"> 5 <div id="shared" style="text-align: right; margin-top: 1rem;">
6 <el-tabs v-model="tabActiveName"> 6 <el-tabs v-model="tabActiveName">
7 <el-tab-pane label="实时视频" name="media"> 7 <el-tab-pane label="实时视频" name="media">
@@ -26,20 +26,6 @@ @@ -26,20 +26,6 @@
26 <!--{"code":0,"data":{"paths":["22-29-30.mp4"],"rootPath":"/home/kkkkk/Documents/ZLMediaKit/release/linux/Debug/www/record/hls/kkkkk/2020-05-11/"}}--> 26 <!--{"code":0,"data":{"paths":["22-29-30.mp4"],"rootPath":"/home/kkkkk/Documents/ZLMediaKit/release/linux/Debug/www/record/hls/kkkkk/2020-05-11/"}}-->
27 <el-tab-pane label="录像查询" name="record"> 27 <el-tab-pane label="录像查询" name="record">
28 <el-date-picker size="mini" v-model="videoHistory.date" type="date" value-format="yyyy-MM-dd" placeholder="日期" @change="queryRecords()"></el-date-picker> 28 <el-date-picker size="mini" v-model="videoHistory.date" type="date" value-format="yyyy-MM-dd" placeholder="日期" @change="queryRecords()"></el-date-picker>
29 - <!-- <el-slider style="margin: 0 1rem 1rem 1rem;"-->  
30 - <!-- v-model="timeVal"-->  
31 - <!-- :min="timeMin"-->  
32 - <!-- :max="timeMax"-->  
33 - <!-- :step="5"-->  
34 - <!-- :marks="getTimeMakrs()"-->  
35 - <!-- :format-tooltip="formatTooltip">-->  
36 - <!-- </el-slider>-->  
37 - <!-- <range-slider :min="timeMin"-->  
38 - <!-- :max="timeMax"-->  
39 - <!-- :step="5"></range-slider>-->  
40 -  
41 - <!-- <el-date-picker v-model="videoHistory.endTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" placeholder="结束时间"-->  
42 - <!-- @change="recordList()"></el-date-picker>-->  
43 <el-table :data="videoHistory.searchHistoryResult" height="150" v-loading="recordsLoading"> 29 <el-table :data="videoHistory.searchHistoryResult" height="150" v-loading="recordsLoading">
44 <el-table-column label="名称" prop="name"></el-table-column> 30 <el-table-column label="名称" prop="name"></el-table-column>
45 <el-table-column label="文件" prop="filePath"></el-table-column> 31 <el-table-column label="文件" prop="filePath"></el-table-column>
@@ -143,41 +129,16 @@ export default { @@ -143,41 +129,16 @@ export default {
143 date: '', 129 date: '',
144 searchHistoryResult: [] //媒体流历史记录搜索结果 130 searchHistoryResult: [] //媒体流历史记录搜索结果
145 }, 131 },
146 - timeMakrs: {  
147 - // 0 : "0:00",  
148 - // // 60 : "1:00",  
149 - // 120 : "2:00",  
150 - // // 180 : "3:00",  
151 - // 240 : "4:00",  
152 - // // 300 : "5:00",  
153 - // 360 : "6:00",  
154 - // // 420 : "7:00",  
155 - // 480 : "8:00",  
156 - // 540 : "9:00",  
157 - 600: "10:00",  
158 - // 660 : "11:00",  
159 - 720: "12:00",  
160 - // 780 : "13:00",  
161 - 840: "14:00",  
162 - // 900 : "15:00",  
163 - 960: "16:00",  
164 - // 1020 : "17:00",  
165 - 1080: "18:00",  
166 - // 1140 : "19:00",  
167 - // 1200 : "20:00",  
168 - // // 1260 : "21:00",  
169 - // 1320 : "22:00",  
170 - // // 1380 : "23:00",  
171 - // 1440 : "24:00"  
172 - },  
173 showVideoDialog: false, 132 showVideoDialog: false,
174 ssrc: '', 133 ssrc: '',
  134 + convertKey: '',
175 deviceId: '', 135 deviceId: '',
176 channelId: '', 136 channelId: '',
177 tabActiveName: 'media', 137 tabActiveName: 'media',
178 hasaudio: false, 138 hasaudio: false,
179 loadingRecords: false, 139 loadingRecords: false,
180 recordsLoading: false, 140 recordsLoading: false,
  141 + isLoging: false,
181 timeVal: 0, 142 timeVal: 0,
182 timeMin: 0, 143 timeMin: 0,
183 timeMax: 1440, 144 timeMax: 1440,
@@ -200,6 +161,7 @@ export default { @@ -200,6 +161,7 @@ export default {
200 this.$refs.videoPlayer.pause(); 161 this.$refs.videoPlayer.pause();
201 } 162 }
202 163
  164 +
203 switch (tab) { 165 switch (tab) {
204 case "media": 166 case "media":
205 this.play(param.streamInfo, param.hasAudio) 167 this.play(param.streamInfo, param.hasAudio)
@@ -217,33 +179,97 @@ export default { @@ -217,33 +179,97 @@ export default {
217 timeAxisSelTime: function (val) { 179 timeAxisSelTime: function (val) {
218 console.log(val) 180 console.log(val)
219 }, 181 },
220 - getTimeMakrs() {  
221 - return this.timeMakrs;  
222 - },  
223 play: function (streamInfo, hasAudio) { 182 play: function (streamInfo, hasAudio) {
224 this.hasaudio = hasAudio; 183 this.hasaudio = hasAudio;
225 - // 根据媒体流信息二次判断  
226 - var realHasAudio = false;  
227 - if (!!streamInfo.tracks && streamInfo.tracks.length > 0 && hasAudio) { 184 + var that = this;
  185 + that.isLoging = false;
  186 + if (!!streamInfo.tracks && streamInfo.tracks.length > 0 ) {
228 for (let i = 0; i < streamInfo.tracks.length; i++) { 187 for (let i = 0; i < streamInfo.tracks.length; i++) {
229 - if (streamInfo.tracks[i].codec_type == 1 && streamInfo.tracks[i].codec_id_name == "CodecAAC") { // 判断为AAC音频  
230 - realHasAudio = true;  
231 - } 188 + if (streamInfo.tracks[i].codec_type == 0 && streamInfo.tracks[i].codec_id_name != "CodecH264") { // 判断为H265视频
  189 + that.coverPlay(streamInfo, streamInfo.tracks[i].codec_id_name, ()=>{
  190 + that.close();
  191 + return;
  192 + })
  193 + }else if (streamInfo.tracks[i].codec_type == 1 && streamInfo.tracks[i].codec_id_name != "CodecAAC") {
  194 + that.coverPlay(streamInfo, streamInfo.tracks[i].codec_id_name, ()=>{
  195 + that.playFromStreamInfo(false. streamInfo)
  196 + })
  197 + }else if (streamInfo.tracks[i].codec_type == 1 && streamInfo.tracks[i].codec_id_name == "CodecAAC") {
  198 + that.playFromStreamInfo(true, streamInfo)
  199 + }else {
  200 + that.playFromStreamInfo(false, streamInfo)
  201 + }
232 } 202 }
  203 + }else {
  204 + that.playFromStreamInfo(false, streamInfo)
233 } 205 }
234 - this.hasaudio = realHasAudio && this.hasaudio;  
235 - this.ssrc = streamInfo.ssrc;  
236 - // this.$refs.videoPlayer.hasaudio = hasAudio;  
237 - // this.videoUrl = streamInfo.flv + "?" + new Date().getTime();  
238 - this.videoUrl = streamInfo.ws_flv;  
239 - this.showVideoDialog = true;  
240 - console.log(this.ssrc); 206 + },
  207 + coverPlay: function (streamInfo, codec_id_name, catchcallback) {
  208 + var that = this;
  209 +
  210 + that.$confirm(codec_id_name + ' 编码格式不支持播放, 是否转码播放?', '提示', {
  211 + confirmButtonText: '确定',
  212 + cancelButtonText: '取消',
  213 + type: 'warning'
  214 + }).then(() => {
  215 + that.isLoging = true;
  216 + that.$axios({
  217 + method: 'post',
  218 + url: '/api/play/' + streamInfo.ssrc + '/convert'
  219 + }).then(function (res) {
  220 + if (res.data.code == 0) {
  221 + streamInfo.ws_flv = res.data.ws_flv;
  222 + that.convertKey = res.data.key;
  223 + setTimeout(()=>{
  224 + that.isLoging = false;
  225 + that.playFromStreamInfo(false, streamInfo);
  226 + }, 2000)
  227 + } else {
  228 + that.isLoging = false;
  229 + that.$message({
  230 + showClose: true,
  231 + message: '转码失败',
  232 + type: 'error'
  233 + });
  234 + }
  235 + }).catch(function (e) {
  236 + that.$message({
  237 + showClose: true,
  238 + message: '播放错误',
  239 + type: 'error'
  240 + });
  241 + });
  242 + }).catch(function (e) {
  243 + if (catchcallback)catchcallback()
  244 + });
  245 + },
  246 + playFromStreamInfo: function (realHasAudio, streamInfo) {
  247 + this.videoUrl = streamInfo.ws_flv;
  248 + this.showVideoDialog = true;
  249 + this.hasaudio = realHasAudio && this.hasaudio;
  250 + this.ssrc = streamInfo.ssrc;
  251 + console.log(this.ssrc);
241 }, 252 },
242 close: function () { 253 close: function () {
243 console.log('关闭视频'); 254 console.log('关闭视频');
244 - this.$refs.videoPlayer.pause(); 255 + if (!this.$refs.videoPlayer){
  256 + this.$refs.videoPlayer.pause();
  257 + }
245 this.videoUrl = ''; 258 this.videoUrl = '';
246 this.showVideoDialog = false; 259 this.showVideoDialog = false;
  260 + if (this.convertKey != '') {
  261 + this.$axios({
  262 + method: 'post',
  263 + url: '/api/play/convert/stop/' + this.convertKey
  264 + }).then(function (res) {
  265 + if (res.data.code == 0) {
  266 + console.log(res.data.msg)
  267 + }else {
  268 + console.error(res.data.msg)
  269 + }
  270 + }).catch(function (e) {});
  271 + }
  272 + this.convertKey = ''
247 }, 273 },
248 copySharedInfo: function (data) { 274 copySharedInfo: function (data) {
249 console.log('复制内容:' + data); 275 console.log('复制内容:' + data);