前端接入 海康威视摄像头视频(可扩展其他厂家),接入协议 rtsp、hls、ws(针对海康) 【P1】

前端接入 海康威视摄像头视频(可扩展其他厂家),接入协议 rtsp、hls、ws(针对海康) 【P1】

作者环境

  • java 1.8.281
  • 后端jeecgboot框架
  • 前端jeecgboot配套的前端框架
  • Vue3

实现思路

  • 由于厂家服务器,可能因为各种原因,不能开发某些协议的端口,捡可用的协议播放即可
  • 海康厂家提供账号Ak,Sk,后端代理获取各种资料
  • 针对hls协议,前端通过hls.js可以直接播放
  • 针对rtsp协议,由于web前端无法直接播放,需要后端通过ffmpeg代为转成hls格式后,由前端通过hls.js播放
  • 针对ws(针对海康)协议,海康提供了前端SDK,获得播放地址后直接调用即可

后端实现

依赖引入
xml
复制代码
<dependency> <groupId>com.hikvision.ga</groupId> <artifactId>artemis-http-client</artifactId> <version>1.1.12.RELEASE</version> </dependency>
控制器接口
  • 用到的实体类
java
复制代码
package org.jeecg.modules.videoplayplus.entity; import lombok.Data; import java.util.List; // 请求实体类 @Data public class PlayReq { // 厂商id 自定义的方便区分不同厂商 String makerId; // 账号的id 自定义的方便区分同一个厂商的不同账号 String akSkId; // 海康请求信息 ============================ // 地区码列表 获取视频点位时候会用到 List<String> regionIndexCodes; // 摄像头视频码 获取预览地址,云台控制 时候会用到 String cameraIndexCode; // 协议名称 获取预览地址时候指明获取那个协议的预览地址 String protocol; // 在使用rtsp协议的时候,用来拼接预览地址 String webProxyBackPath; // 云台控制 1停止 0运动 Integer action; // 云台控制命令 up向上 left向左动 xoom_in放大 等等具体参照海康安防平台 String command; // 海康请求信息 ============================ }
java
复制代码
package org.jeecg.modules.videoplayplus.entity; import lombok.Builder; import lombok.Data; // 响应实体类 @Data @Builder public class PlayResp { Boolean done; Object data; // 海康协议 参数集========== Integer delay; // 海康协议 参数集========== }
  • 视频资源控制器
java
复制代码
package org.jeecg.modules.videoplayplus.controller; import lombok.extern.slf4j.Slf4j; import org.jeecg.common.api.vo.Result; import org.jeecg.modules.videoplayplus.entity.PlayReq; import org.jeecg.modules.videoplayplus.service.VideoPlayService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/new/hkvideohelper") @Slf4j public class VideoPlayController { @Autowired VideoPlayService videoPlayService; // 获得视频地点树的接口 @GetMapping("/tree") public Result<?> tree(PlayReq playReq) { return videoPlayService.tree(playReq); } // 获得视频点位的 @PostMapping("/camera-list") public Result<?> cameraList(@RequestBody PlayReq playReq) { return videoPlayService.cameraList(playReq); } // 获取视频预览地址 @GetMapping("/play-url") public Result<?> playUrl(PlayReq playReq) { return videoPlayService.playUrl(playReq); } // 摄像头云台控制 @GetMapping("/yun-control") public Result<?> yunControl(PlayReq playReq) { return videoPlayService.yunControl(playReq); } }
java
复制代码
package org.jeecg.modules.videoplayplus.controller; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.jeecg.modules.videoplayplus.util.pub.ConversionProtocol; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.HashMap; // m3u8文件代理转发接口 @RestController @RequestMapping("/new/video-file") @Slf4j public class FileController { // 协议转化服务 @Autowired ConversionProtocol conversionProtocol; // m3u8文件代理转发接口 @GetMapping("/video/{m3u8Id}/{name}") public void hlsPush(String preflight, @PathVariable String m3u8Id, @PathVariable String name, HttpServletResponse response) throws IOException { byte[] bytes = conversionProtocol.readVideoFile(m3u8Id, name); ServletOutputStream outputStream = response.getOutputStream(); if (preflight != null) { HashMap<String, Object> map = new HashMap<>(); if (bytes == null) { map.put("state", 0); } else { map.put("state", 1); } String jsonString = JSON.toJSONString(map); IoUtil.write(outputStream, true, jsonString.getBytes(StandardCharsets.UTF_8)); return; } response.setHeader("Content-Type", "application/octet-stream"); response.setHeader("CAccess-Control-Allow-Headers", "*"); response.setHeader("Access-Control-Max-Age", "1728000"); if (bytes != null) { IoUtil.write(outputStream, true, bytes); } } }
服务层
  • 服务层
java
复制代码
package org.jeecg.modules.videoplayplus.service; import org.jeecg.common.api.vo.Result; import org.jeecg.modules.videoplayplus.entity.PlayReq; import org.jeecg.modules.videoplayplus.util.IVideoPlay; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; @Service public class VideoPlayService { HashMap<String, IVideoPlay> iPlay = new HashMap<>(); public VideoPlayService(ApplicationContext context) { Map<String, IVideoPlay> iPlay = context.getBeansOfType(IVideoPlay.class); iPlay.forEach((s, iVideoPlay) -> this.iPlay.put(iVideoPlay.getMakerId(), iVideoPlay)); } public Result<?> tree(PlayReq playReq) { if (!iPlay.containsKey(playReq.getMakerId())) return Result.error("不存在的厂商"); return Result.OK(iPlay.get(playReq.getMakerId()).tree(playReq)); } public Result<?> cameraList(PlayReq playReq) { if (!iPlay.containsKey(playReq.getMakerId())) return Result.error("不存在的厂商"); return Result.OK(iPlay.get(playReq.getMakerId()).cameraList(playReq)); } public Result<?> playUrl(PlayReq playReq) { if (!iPlay.containsKey(playReq.getMakerId())) return Result.error("不存在的厂商"); return Result.OK(iPlay.get(playReq.getMakerId()).playUrl(playReq)); } public Result<?> yunControl(PlayReq playReq) { if (!iPlay.containsKey(playReq.getMakerId())) return Result.error("不存在的厂商"); return Result.OK(iPlay.get(playReq.getMakerId()).yunControl(playReq)); } }
  • 规定统一接口、注解,方便不同厂商时,只需要实现固定接口即可接入
java
复制代码
package org.jeecg.modules.videoplayplus.util; import org.jeecg.modules.videoplayplus.entity.PlayReq; import org.jeecg.modules.videoplayplus.entity.PlayResp; public interface IVideoPlay { String getMakerId(); PlayResp tree(PlayReq playReq); PlayResp cameraList(PlayReq playReq); PlayResp playUrl(PlayReq playReq); PlayResp yunControl(PlayReq playReq); }
java
复制代码
package org.jeecg.modules.videoplayplus.util; import org.springframework.stereotype.Component; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) // 运行时注解 @Target({ElementType.TYPE}) @Component public @interface VideoPlay { // 标记所有厂商的实现类 }

结语

  • 由于太多,这期先实现这么多
  • 下期,会编写海康威视厂家的播放实现类

最终目录结构

video-1.png

传送门

下一期,P2传送门

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP