Commit 9ae0691c806b6b56306c2cda5509b0a0444cec06

Authored by 648540858
1 parent 936adf31

优化快照的存储与显示

src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -91,10 +91,9 @@ public class ZLMHttpHookListener { @@ -91,10 +91,9 @@ public class ZLMHttpHookListener {
91 public ResponseEntity<String> onServerKeepalive(@RequestBody JSONObject json){ 91 public ResponseEntity<String> onServerKeepalive(@RequestBody JSONObject json){
92 92
93 if (logger.isDebugEnabled()) { 93 if (logger.isDebugEnabled()) {
94 - logger.debug("[ ZLM HOOK ]on_server_keepalive API调用,参数:" + json.toString()); 94 + logger.debug("[ ZLM HOOK ] on_server_keepalive API调用,参数:" + json.toString());
95 } 95 }
96 String mediaServerId = json.getString("mediaServerId"); 96 String mediaServerId = json.getString("mediaServerId");
97 -  
98 List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_keepalive); 97 List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_keepalive);
99 if (subscribes != null && subscribes.size() > 0) { 98 if (subscribes != null && subscribes.size() > 0) {
100 for (ZLMHttpHookSubscribe.Event subscribe : subscribes) { 99 for (ZLMHttpHookSubscribe.Event subscribe : subscribes) {
@@ -164,7 +163,6 @@ public class ZLMHttpHookListener { @@ -164,7 +163,6 @@ public class ZLMHttpHookListener {
164 if (mediaInfo != null) { 163 if (mediaInfo != null) {
165 subscribe.response(mediaInfo, json); 164 subscribe.response(mediaInfo, json);
166 } 165 }
167 -  
168 } 166 }
169 JSONObject ret = new JSONObject(); 167 JSONObject ret = new JSONObject();
170 ret.put("code", 0); 168 ret.put("code", 0);
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
@@ -151,7 +151,7 @@ public class ZLMRESTfulUtils { @@ -151,7 +151,7 @@ public class ZLMRESTfulUtils {
151 } 151 }
152 152
153 } 153 }
154 - File snapFile = new File(targetPath + "/" + fileName); 154 + File snapFile = new File(targetPath + File.separator + fileName);
155 FileOutputStream outStream = new FileOutputStream(snapFile); 155 FileOutputStream outStream = new FileOutputStream(snapFile);
156 156
157 outStream.write(Objects.requireNonNull(response.body()).bytes()); 157 outStream.write(Objects.requireNonNull(response.body()).bytes());
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -123,36 +123,19 @@ public class PlayServiceImpl implements IPlayService { @@ -123,36 +123,19 @@ public class PlayServiceImpl implements IPlayService {
123 result.onCompletion(()->{ 123 result.onCompletion(()->{
124 // 点播结束时调用截图接口 124 // 点播结束时调用截图接口
125 // TODO 应该在上流时调用更好,结束也可能是错误结束 125 // TODO 应该在上流时调用更好,结束也可能是错误结束
126 - try {  
127 - String classPath = ResourceUtils.getURL("classpath:").getPath();  
128 - // 兼容打包为jar的class路径  
129 - if(classPath.contains("jar")) {  
130 - classPath = classPath.substring(0, classPath.lastIndexOf("."));  
131 - classPath = classPath.substring(0, classPath.lastIndexOf("/") + 1); 126 + String path = "snap";
  127 + String fileName = deviceId + "_" + channelId + ".jpg";
  128 + ResponseEntity responseEntity = (ResponseEntity)result.getResult();
  129 + if (responseEntity != null && responseEntity.getStatusCode() == HttpStatus.OK) {
  130 + WVPResult wvpResult = (WVPResult)responseEntity.getBody();
  131 + if (Objects.requireNonNull(wvpResult).getCode() == 0) {
  132 + StreamInfo streamInfoForSuccess = (StreamInfo)wvpResult.getData();
  133 + MediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId());
  134 + String streamUrl = streamInfoForSuccess.getFmp4();
  135 + // 请求截图
  136 + logger.info("[请求截图]: " + fileName);
  137 + zlmresTfulUtils.getSnap(mediaInfo, streamUrl, 15, 1, path, fileName);
132 } 138 }
133 - if (classPath.startsWith("file:")) {  
134 - classPath = classPath.substring(classPath.indexOf(":") + 1);  
135 - }  
136 - String path = classPath + "static/static/snap/";  
137 - // 兼容Windows系统路径(去除前面的“/”)  
138 - if(System.getProperty("os.name").contains("indows")) {  
139 - path = path.substring(1);  
140 - }  
141 - String fileName = deviceId + "_" + channelId + ".jpg";  
142 - ResponseEntity responseEntity = (ResponseEntity)result.getResult();  
143 - if (responseEntity != null && responseEntity.getStatusCode() == HttpStatus.OK) {  
144 - WVPResult wvpResult = (WVPResult)responseEntity.getBody();  
145 - if (Objects.requireNonNull(wvpResult).getCode() == 0) {  
146 - StreamInfo streamInfoForSuccess = (StreamInfo)wvpResult.getData();  
147 - MediaServerItem mediaInfo = mediaServerService.getOne(streamInfoForSuccess.getMediaServerId());  
148 - String streamUrl = streamInfoForSuccess.getFmp4();  
149 - // 请求截图  
150 - logger.info("[请求截图]: " + fileName);  
151 - zlmresTfulUtils.getSnap(mediaInfo, streamUrl, 15, 1, path, fileName);  
152 - }  
153 - }  
154 - } catch (FileNotFoundException e) {  
155 - e.printStackTrace();  
156 } 139 }
157 }); 140 });
158 if (streamInfo != null) { 141 if (streamInfo != null) {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -21,16 +21,22 @@ import io.swagger.annotations.Api; @@ -21,16 +21,22 @@ import io.swagger.annotations.Api;
21 import io.swagger.annotations.ApiImplicitParam; 21 import io.swagger.annotations.ApiImplicitParam;
22 import io.swagger.annotations.ApiImplicitParams; 22 import io.swagger.annotations.ApiImplicitParams;
23 import io.swagger.annotations.ApiOperation; 23 import io.swagger.annotations.ApiOperation;
  24 +import org.apache.commons.compress.utils.IOUtils;
  25 +import org.apache.http.HttpResponse;
24 import org.slf4j.Logger; 26 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory; 27 import org.slf4j.LoggerFactory;
26 import org.springframework.beans.factory.annotation.Autowired; 28 import org.springframework.beans.factory.annotation.Autowired;
27 import org.springframework.http.HttpStatus; 29 import org.springframework.http.HttpStatus;
  30 +import org.springframework.http.MediaType;
28 import org.springframework.http.ResponseEntity; 31 import org.springframework.http.ResponseEntity;
29 import org.springframework.util.StringUtils; 32 import org.springframework.util.StringUtils;
30 import org.springframework.web.bind.annotation.*; 33 import org.springframework.web.bind.annotation.*;
31 import org.springframework.web.context.request.async.DeferredResult; 34 import org.springframework.web.context.request.async.DeferredResult;
32 35
  36 +import javax.servlet.http.HttpServletResponse;
33 import javax.sip.DialogState; 37 import javax.sip.DialogState;
  38 +import java.io.*;
  39 +import java.nio.file.Files;
34 import java.util.*; 40 import java.util.*;
35 41
36 @Api(tags = "国标设备查询", value = "国标设备查询") 42 @Api(tags = "国标设备查询", value = "国标设备查询")
@@ -456,4 +462,17 @@ public class DeviceQuery { @@ -456,4 +462,17 @@ public class DeviceQuery {
456 wvpResult.setData(dialogStateMap); 462 wvpResult.setData(dialogStateMap);
457 return wvpResult; 463 return wvpResult;
458 } 464 }
  465 +
  466 + @GetMapping("/snap/{deviceId}/{channelId}")
  467 + @ApiOperation(value = "请求截图", notes = "请求截图")
  468 + public void getSnap(HttpServletResponse resp, @PathVariable String deviceId, @PathVariable String channelId) {
  469 +
  470 + try {
  471 + final InputStream in = Files.newInputStream(new File("snap" + File.separator + deviceId + "_" + channelId + ".jpg").toPath());
  472 + resp.setContentType(MediaType.IMAGE_PNG_VALUE);
  473 + IOUtils.copy(in, resp.getOutputStream());
  474 + } catch (IOException e) {
  475 + resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
  476 + }
  477 + }
459 } 478 }
web_src/src/components/channelList.vue
@@ -39,21 +39,22 @@ @@ -39,21 +39,22 @@
39 </el-table-column> 39 </el-table-column>
40 <el-table-column label="快照" width="80" align="center"> 40 <el-table-column label="快照" width="80" align="center">
41 <template slot-scope="scope"> 41 <template slot-scope="scope">
42 - <img style="max-height: 3rem;max-width: 4rem;"  
43 - v-if="scope.row.subCount === 0 && scope.row.parental === 0"  
44 - :id="scope.row.deviceId + '_' + scope.row.channelId"  
45 - :src="getSnap(scope.row)"  
46 - @error="getSnapErrorEvent($event.target.id)"  
47 - alt="">  
48 - <!-- <el-image-->  
49 - <!-- :id="'snapImg_' + scope.row.deviceId + '_' + scope.row.channelId"-->  
50 - <!-- :src="getSnap(scope.row)"-->  
51 - <!-- @error="getSnapErrorEvent($event, scope.row)"-->  
52 - <!-- :fit="'contain'">-->  
53 - <!-- <div slot="error" class="image-slot">-->  
54 - <!-- <i class="el-icon-picture-outline"></i>-->  
55 - <!-- </div>-->  
56 - <!-- </el-image>--> 42 +<!-- <img style="max-height: 3rem;max-width: 4rem;"-->
  43 +<!-- v-if="scope.row.subCount === 0 && scope.row.parental === 0"-->
  44 +<!-- :deviceId="scope.row.deviceId"-->
  45 +<!-- :channelId="scope.row.channelId"-->
  46 +<!-- :src="getSnap(scope.row)"-->
  47 +<!-- @error="getSnapErrorEvent($event.target.deviceId, $event.target.channelId)"-->
  48 +<!-- alt="">-->
  49 + <el-image
  50 + :src="getSnap(scope.row)"
  51 + :preview-src-list="getBigSnap(scope.row)"
  52 + @error="getSnapErrorEvent(scope.row.deviceId, cope.row.channelId)"
  53 + :fit="'contain'">
  54 + <div slot="error" class="image-slot">
  55 + <i class="el-icon-picture-outline"></i>
  56 + </div>
  57 + </el-image>
57 </template> 58 </template>
58 </el-table-column> 59 </el-table-column>
59 <el-table-column prop="subCount" label="子节点数"> 60 <el-table-column prop="subCount" label="子节点数">
@@ -227,7 +228,7 @@ export default { @@ -227,7 +228,7 @@ export default {
227 setTimeout(() => { 228 setTimeout(() => {
228 229
229 let snapId = deviceId + "_" + channelId; 230 let snapId = deviceId + "_" + channelId;
230 - that.loadSnap[snapId] = 0; 231 + that.loadSnap[deviceId + channelId] = 0;
231 that.getSnapErrorEvent(snapId) 232 that.getSnapErrorEvent(snapId)
232 }, 5000) 233 }, 5000)
233 that.$refs.devicePlayer.openDialog("media", deviceId, channelId, { 234 that.$refs.devicePlayer.openDialog("media", deviceId, channelId, {
@@ -269,19 +270,24 @@ export default { @@ -269,19 +270,24 @@ export default {
269 }); 270 });
270 }, 271 },
271 getSnap: function (row) { 272 getSnap: function (row) {
272 - return '/static/snap/' + row.deviceId + '_' + row.channelId + '.jpg' 273 + let url = (process.env.NODE_ENV === 'development'? "debug": "") + '/api/device/query/snap/' + row.deviceId + '/' + row.channelId
  274 + return url
273 }, 275 },
274 - getSnapErrorEvent: function (id) { 276 + getBigSnap: function (row) {
  277 + return [this.getSnap(row)]
  278 + },
  279 + getSnapErrorEvent: function (deviceId, channelId) {
275 280
276 - if (typeof (this.loadSnap[id]) != "undefined") {  
277 - console.log("下载截图" + this.loadSnap[id])  
278 - if (this.loadSnap[id] > 5) {  
279 - delete this.loadSnap[id]; 281 + if (typeof (this.loadSnap[deviceId + channelId]) != "undefined") {
  282 + console.log("下载截图" + this.loadSnap[deviceId + channelId])
  283 + if (this.loadSnap[deviceId + channelId] > 5) {
  284 + delete this.loadSnap[deviceId + channelId];
280 return; 285 return;
281 } 286 }
282 setTimeout(() => { 287 setTimeout(() => {
283 - this.loadSnap[id]++  
284 - document.getElementById(id).setAttribute("src", '/static/snap/' + id + '.jpg?' + new Date().getTime()) 288 + let url = (process.env.NODE_ENV === 'development'? "debug": "") + '/api/device/query/snap/' + deviceId + '/' + channelId
  289 + this.loadSnap[deviceId + channelId]++
  290 + document.getElementById(deviceId + channelId).setAttribute("src", url + '?' + new Date().getTime())
285 }, 1000) 291 }, 1000)
286 292
287 } 293 }