最近在玩视频相关的,也算是一步一步的深入吧。

第一版:

用海康SDK进行历史数据下载:

https://blog.csdn.net/qq_16504067/article/details/114538622?spm=1001.2014.3001.5502

https://blog.csdn.net/qq_16504067/article/details/114577693?spm=1001.2014.3001.5502

用ffmgeg转rtsp格式为rtmp格式存储到http-flv的直播流媒体服务器,然后前端直接拉取rtmp流进行播放

https://blog.csdn.net/qq_16504067/article/details/115503882?spm=1001.2014.3001.5502

https://github.com/eguid/FFCH4J

第二版:

问了海康的技术支持说他们是PS流,所以只需要解析PS流成前端可以播放的就行,现在在网上找到了一个wfs.js(https://github.com/MarkRepo/wfs.js)可以播放裸流H264,所以我就想在PS流中解析出H264的裸流,然后给wfs.js进行播放

https://blog.csdn.net/qq_16504067/article/details/117781017?spm=1001.2014.3001.5502

https://blog.yasking.org/a/hikvision-rtp-ps-stream-parser.html

https://blog.csdn.net/weixin_44517656/article/details/108412988

看以上的参考文章和c++的这个项目https://github.com/kevinfromcn/PsToH264后自己进行了一次的demo的预览回调解析,我先通过

public static String byteToHex(final byte[] bytes) {String strHex = "";StringBuilder sb = new StringBuilder("");for (int n = 0; n < bytes.length; n++) {strHex = Integer.toHexString(bytes[n] & 0xFF);sb.append((strHex.length() == 1) ? "0" + strHex : strHex); // 每个字节由两个字符表示,位数不够,高位补0// sb.append(" ");}return sb.toString().trim();}

将海康的PS流转成16进制进行答应查看,果然是PS流的格式

然后再按照上面的参考进行解析(因为海康是一段段给的,所以我的解析也进行了简单处理)

/*** 开启/关闭预览* * @return*/public JSONObject startOrStopPreview() {final JSONObject result = new JSONObject();if (lUserID.intValue() == -1) {logger.error("请先登陆....");result.put("status", false);result.put("msg", "请先登陆....");return result;}// 如果预览窗口没打开,不在预览if (bRealPlay == false) {// 要开启预览的通道号int iChannelNum = 1;// 通道号m_strClientInfo = new HCNetSDK.NET_DVR_CLIENTINFO();m_strClientInfo.lChannel = new NativeLong(iChannelNum);// 回调预览m_strClientInfo.hPlayWnd = null;lPreviewHandle = hCNetSDK.NET_DVR_RealPlay_V30(lUserID, m_strClientInfo, fRealDataCallBack, null, true);long previewSucValue = lPreviewHandle.longValue();// 预览失败时:if (previewSucValue == -1) {logger.error("开启预览失败......");result.put("status", false);result.put("msg", "开启预览失败......");return result;}// 预览成功的操作bRealPlay = true;result.put("status", true);result.put("msg", "开始预览成功....");} else {// 如果在预览,停止预览,关闭窗口hCNetSDK.NET_DVR_StopRealPlay(lPreviewHandle);bRealPlay = false;result.put("status", true);result.put("msg", "停止预览成功");}return result;}/******************************************************************************* 内部类: FRealDataCallBack 实现预览回调数据******************************************************************************/class FRealDataCallBack implements HCNetSDK.FRealDataCallBack_V30 {// 预览回调@Overridepublic void invoke(final NativeLong lRealHandle, final int dwDataType, final ByteByReference pBuffer,final int dwBufSize, final Pointer pUser) {switch (dwDataType) {case HCNetSDK.NET_DVR_SYSHEAD: // 系统头case HCNetSDK.NET_DVR_STREAMDATA: // 码流数据if (dwBufSize > 0) {byte[] outputData = pBuffer.getPointer().getByteArray(0, dwBufSize);try {writeESH264(outputData);} catch (IOException e) {e.printStackTrace();}}}}}byte[] allEsBytes = null;/*** 提取H264的裸流写入文件* * @param outputData* @throws IOException*/public void writeESH264(final byte[] outputData) throws IOException {if (outputData.length <= 0) {return;}if ((outputData[0] & 0xff) == 0x00//&& (outputData[1] & 0xff) == 0x00//&& (outputData[2] & 0xff) == 0x01//&& (outputData[3] & 0xff) == 0xBA) {// RTP包开头try {// 一个完整的帧解析完成后将解析的数据放入BlockingQueue,websocket获取后发生给前端if (allEsBytes != null && allEsBytes.length > 0) {MyBlockingQueue.bq.put(allEsBytes);}allEsBytes = null;} catch (InterruptedException e) {e.printStackTrace();}}// 是00 00 01 eo开头的就是视频的pes包if ((outputData[0] & 0xff) == 0x00//&& (outputData[1] & 0xff) == 0x00//&& (outputData[2] & 0xff) == 0x01//&& (outputData[3] & 0xff) == 0xE0) {//// 去掉包头后的起始位置int from = 9 + outputData[8] & 0xff;int len = outputData.length - 9 - (outputData[8] & 0xff);// 获取es裸流byte[] esBytes = new byte[len];System.arraycopy(outputData, from, esBytes, 0, len);if (allEsBytes == null) {allEsBytes = esBytes;} else {byte[] newEsBytes = new byte[allEsBytes.length + esBytes.length];System.arraycopy(allEsBytes, 0, newEsBytes, 0, allEsBytes.length);System.arraycopy(esBytes, 0, newEsBytes, allEsBytes.length, esBytes.length);allEsBytes = newEsBytes;}}}

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicInteger;import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;import org.springframework.stereotype.Component;import com.example.demo.domain.MyBlockingQueue;import lombok.extern.slf4j.Slf4j;/*** 前后端交互的类实现消息的接收推送(自己发送给自己)* * @ServerEndpoint(value = "/wstest") 前端通过此URI和后端交互,建立连接*/
@Slf4j
@ServerEndpoint(value = "/wstest")
@Component
public class OneWebSocket {/** 记录当前在线连接数 */private static AtomicInteger onlineCount = new AtomicInteger(0);/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(final Session session) {onlineCount.incrementAndGet(); // 在线数加1log.info("有新连接加入:{},当前在线人数为:{}", session.getId(), onlineCount.get());while (true) {try {byte[] esBytes = (byte[]) MyBlockingQueue.bq.take();ByteBuffer data = ByteBuffer.wrap(esBytes);session.getBasicRemote().sendBinary(data);} catch (InterruptedException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}public static String byteToHex(final byte[] bytes) {String strHex = "";StringBuilder sb = new StringBuilder("");for (int n = 0; n < bytes.length; n++) {strHex = Integer.toHexString(bytes[n] & 0xFF);sb.append((strHex.length() == 1) ? "0" + strHex : strHex); // 每个字节由两个字符表示,位数不够,高位补0// sb.append(" ");}return sb.toString().trim();}/*** 连接关闭调用的方法*/@OnClosepublic void onClose(final Session session) {onlineCount.decrementAndGet(); // 在线数减1log.info("有一连接关闭:{},当前在线人数为:{}", session.getId(), onlineCount.get());}/*** 收到客户端消息后调用的方法** @param message*            客户端发送过来的消息*/@OnMessagepublic void onMessage(final String message, final Session session) {log.info("服务端收到客户端[{}]的消息:{}", session.getId(), message);}@OnErrorpublic void onError(final Session session, final Throwable error) {log.error("发生错误");error.printStackTrace();}/*** 服务端发送消息给客户端*/private void sendMessage(final String message, final Session toSession) {try {log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message);toSession.getBasicRemote().sendText(message);} catch (Exception e) {log.error("服务端发送消息给客户端失败:{}", e);}}
}

前端:

<!DOCTYPE html>
<html><head><title>h.264 To fmp4</title><script src="js/jquery/jquery-1.12.3.js"> </script><script src="js/wfs.js"></script><link href="js/jquery/jquery-ui.css" rel="stylesheet" type="text/css" /><style type="text/css" media="screen">video.rotate180 {width: 100%;height: 100%;transform: rotateX(180deg);-moz-transform: rotateX(180deg);-webkit-transform: rotateX(180deg);-o-transform: rotateX(180deg);-ms-transform: rotateX(180deg);}</style></head><body><h2>h.264 To fmp4</h2><div class="wfsjs"><video id="video1" muted="muted" controls="controls" style="width: 100%;height: 100%;"autoplay="autoplay" muted></video><div class="ratio"></div></div><script>window.onload = function() {if (Wfs.isSupported()) {var video1 = document.getElementById("video1");var wfs = new Wfs();wfs.attachMedia(video1, 'ch1');}};</script></body>
</html>

注意wfs.js中要修改:

{key: 'onMediaAttached',value: function onMediaAttached(data) {if (data.websocketName != undefined) {//var client = new WebSocket( 'ws://' + window.location.host + '/' +  data.websocketName );//var uri = 'ws://' + '10.122.4.17:18080';//var protocol = 'binary';//var client = new WebSocket(uri, protocol);var client = new WebSocket('ws://10.122.4.17:18080/wstest');this.wfs.attachWebsocket(client, data.channelName);} else {console.log('websocketName ERROE!!!');}}}
{key: 'receiveSocketMessage',value: function receiveSocketMessage(event) {var buffer = new Uint8Array(event.data);this.wfs.trigger(_events2.default.H264_DATA_PARSING, { data:buffer });}}

通过海康SDK预览获取回调的PS流数据自己解析然后前端播放相关推荐

  1. 通过海康sdk实现指定时间段内的录像文件下载

    通过海康sdk实现指定时间段内的录像文件下载 实现方式 录像文件下载实现流程 实现方式 下载录像文件接口 提供获取录像文件下载进度 个人博客:banmajio's blog 海康sdk二次开发系列文章 ...

  2. LiveNVR监控流媒体Onvif/RTSP功能支持海康摄像头通过海康SDK的方式接入直播观看录像回看预置位操作

    LiveNVR功能支持海康摄像头通过海康SDK的方式接入直播观看录像回看预置位操作 1.流媒体服务说明 2.支持海康SDK接入 3.视频广场查看播放 4.预置位接口 4.RTSP/HLS/FLV/RT ...

  3. LiveNVR监控流媒体Onvif/RTSP功能支持海康摄像头通过海康SDK接入支持回看倍速播放海康设备存储的设备录像

    LiveNVR功能支持海康摄像头通过海康SDK接入支持回看倍速播放海康设备存储的设备录像 1.流媒体服务说明 2.支持海康SDK接入 3.查看设备录像 3.1.时间轴模式 3.2.列表模式 4.RTS ...

  4. 最详细的JavaWeb服务器端通过海康SDK实现对摄像机的控制。

    需求介绍: 近期需求,需要通过JavaWeb开发,实现在web页面上对海康摄像机进行调焦.控制方向.调光圈大小等操作.通过研究海康官网给的demo,进行JavaWeb二次开发.同时也欢迎各位小伙伴留言 ...

  5. 音视频实战(海康视频预览,通过ffmpeg转码)

    概述 ​ 本章主要讲解实际工作中遇到的问题,以及如何解决并实现,下面是音视频开发的常用工具,下载地址就不贴了. VLC media player 视频流播放工具 MediaInfo 视频信息查看工具 ...

  6. 【173】VS2022调试通过海康温度报警SDK的C++代码

    具体的开发环境配置方法可以参考 [160]VS2022调试通过海康摄像头烟火识别SDK 操作系统: Windows 需要先在海康平台设置好报警温度,然后就可以编写代码监听警报.此功能可以用于火灾报警的 ...

  7. 【166】VS2022调试通过海康人脸抓拍SDK的C++代码

    具体的开发环境配置方法可以参考 [160]VS2022调试通过海康摄像头烟火识别SDK 下面是人脸抓拍的C++代码,把原来示例中的CreateFile函数改成了CreateFileA函数,避免出现无法 ...

  8. 2019.11.12-最新大华摄像机SDK开发,预览实时视频并指定码流格式保存到文件中(可观看)

    大华摄像机SDK开发,预览实时视频并指定码流格式保存到文件中 由于本人最近在开发大华摄像机,特此分享一些经验给到各位开发朋友,本次实例是关于大华摄像机的实时预览视频码流保存到文件中的Demo,本人还开 ...

  9. Google Assistant SDK预览版发布

    到目前为止,Google Assistant已经可以在Google硬件,Google Home,Android Wear,Pixel手机以及运行Marshmallow和Nougat的Android手机 ...

最新文章

  1. 使用log4jdbc记录SQL信息
  2. Break,Continue,Return 傻傻分不清楚
  3. python 可变参数 关键字参数_Python之 可变参数和关键字参数
  4. oracle avg分析函数,分析函数之sum,avg
  5. 使用ajax将数据显示在指定位置_AJAX学习主题之一
  6. html form src,form.html
  7. dedecms代码研究六
  8. java中如何分隔字符串_Java中分割字符串
  9. 干货:使用Fastapi开发自己的Mock server(附源码)
  10. GAN 的渐进式训练方法 PI-REC:手绘草稿迅速重建为完整图像...
  11. R_地图上的迷你直方图
  12. BZOJ2521[SHOI2010] 最小生成树
  13. 二维码扫码功能流程图
  14. 计算机休眠和睡眠省电,几步教会你笔记本睡眠和休眠有什么区别
  15. 用Matplotlib实现世界GDP动态排名
  16. USB-C PD接口DRP芯片功能介绍
  17. android安装教程!深入理解Flutter动画原理,大厂面试题汇总
  18. rpath添加依赖库搜索路径
  19. 用友u8计算机快捷键,用友U8快捷键一览表
  20. 打开任务管理器只显示任务 不显示进程了怎么办?

热门文章

  1. 网安之php开发第十五天
  2. MySQL——insert注意事项
  3. 新闻|“新”伙伴—智链万源加入VMware创新网络“威睿加速计划日”
  4. BigDecimal和DecimalFormat
  5. 2. 认识O(logN)的排序
  6. 江西理工大学教育邮箱登录(2021年)
  7. 生物信息学入门 GEO芯片数据差异表达分析时是否需要log2以及标准化的问题
  8. JAVA输出菱形并使用绝对值_利用for循环打印实心棱形和空心棱形
  9. android 实现发送彩信方法 (mms),非调用,android 实现发送彩信方法 (MMS),非调用系统界面...
  10. mysql导入sql文件、数据库时报错ERROR: ASCII '\0' appeared in the statement