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 | 91 | public ResponseEntity<String> onServerKeepalive(@RequestBody JSONObject json){ |
| 92 | 92 | |
| 93 | 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 | 96 | String mediaServerId = json.getString("mediaServerId"); |
| 97 | - | |
| 98 | 97 | List<ZLMHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(ZLMHttpHookSubscribe.HookType.on_server_keepalive); |
| 99 | 98 | if (subscribes != null && subscribes.size() > 0) { |
| 100 | 99 | for (ZLMHttpHookSubscribe.Event subscribe : subscribes) { |
| ... | ... | @@ -164,7 +163,6 @@ public class ZLMHttpHookListener { |
| 164 | 163 | if (mediaInfo != null) { |
| 165 | 164 | subscribe.response(mediaInfo, json); |
| 166 | 165 | } |
| 167 | - | |
| 168 | 166 | } |
| 169 | 167 | JSONObject ret = new JSONObject(); |
| 170 | 168 | ret.put("code", 0); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
| ... | ... | @@ -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 | 155 | FileOutputStream outStream = new FileOutputStream(snapFile); |
| 156 | 156 | |
| 157 | 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 | 123 | result.onCompletion(()->{ |
| 124 | 124 | // 点播结束时调用截图接口 |
| 125 | 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 | 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 | 21 | import io.swagger.annotations.ApiImplicitParam; |
| 22 | 22 | import io.swagger.annotations.ApiImplicitParams; |
| 23 | 23 | import io.swagger.annotations.ApiOperation; |
| 24 | +import org.apache.commons.compress.utils.IOUtils; | |
| 25 | +import org.apache.http.HttpResponse; | |
| 24 | 26 | import org.slf4j.Logger; |
| 25 | 27 | import org.slf4j.LoggerFactory; |
| 26 | 28 | import org.springframework.beans.factory.annotation.Autowired; |
| 27 | 29 | import org.springframework.http.HttpStatus; |
| 30 | +import org.springframework.http.MediaType; | |
| 28 | 31 | import org.springframework.http.ResponseEntity; |
| 29 | 32 | import org.springframework.util.StringUtils; |
| 30 | 33 | import org.springframework.web.bind.annotation.*; |
| 31 | 34 | import org.springframework.web.context.request.async.DeferredResult; |
| 32 | 35 | |
| 36 | +import javax.servlet.http.HttpServletResponse; | |
| 33 | 37 | import javax.sip.DialogState; |
| 38 | +import java.io.*; | |
| 39 | +import java.nio.file.Files; | |
| 34 | 40 | import java.util.*; |
| 35 | 41 | |
| 36 | 42 | @Api(tags = "国标设备查询", value = "国标设备查询") |
| ... | ... | @@ -456,4 +462,17 @@ public class DeviceQuery { |
| 456 | 462 | wvpResult.setData(dialogStateMap); |
| 457 | 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 | 39 | </el-table-column> |
| 40 | 40 | <el-table-column label="快照" width="80" align="center"> |
| 41 | 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 | 58 | </template> |
| 58 | 59 | </el-table-column> |
| 59 | 60 | <el-table-column prop="subCount" label="子节点数"> |
| ... | ... | @@ -227,7 +228,7 @@ export default { |
| 227 | 228 | setTimeout(() => { |
| 228 | 229 | |
| 229 | 230 | let snapId = deviceId + "_" + channelId; |
| 230 | - that.loadSnap[snapId] = 0; | |
| 231 | + that.loadSnap[deviceId + channelId] = 0; | |
| 231 | 232 | that.getSnapErrorEvent(snapId) |
| 232 | 233 | }, 5000) |
| 233 | 234 | that.$refs.devicePlayer.openDialog("media", deviceId, channelId, { |
| ... | ... | @@ -269,19 +270,24 @@ export default { |
| 269 | 270 | }); |
| 270 | 271 | }, |
| 271 | 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 | 285 | return; |
| 281 | 286 | } |
| 282 | 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 | 291 | }, 1000) |
| 286 | 292 | |
| 287 | 293 | } | ... | ... |