Commit 9ae0691c806b6b56306c2cda5509b0a0444cec06
1 parent
936adf31
优化快照的存储与显示
Showing
5 changed files
with
63 additions
and
57 deletions
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 | } |