推荐 最新
我买了30万的鞋子

java接入海康威视摄像头sdk后,如何推流给前端?

海康提供的demo用的Java Swing开发的GUI程序,怎么把这个视频转到前端vue项目,后端是怎么生成流地址? *** 之前贴的代码我删了,我重新整理了一下,有懂得大佬来指导一下 开发背景:目前开发环境是摄像头直接连接我本地电脑做开发,springboot框架,不走云视频,本地调海康的SDK得到视频流 我的想法:本地搭建一个流媒体服务ZLMediaKit,海康回调的视频流我通过java代码推到这个流媒体服务上,然后前端vue再去从这个流媒体服务上的rtsp地址直接拉流? 下面是业务类,项目启动时调用,ClientHikVision是从海康demo整理出来的 @Service public class EquipmentHikVisionServiceImpl implements EquipmentHikVisionService { @Override @PostConstruct public void register() { ClientHikVision clientHikVision = new ClientHikVision(); clientHikVision.initPipedStream(); clientHikVision.clientInit(); clientHikVision.action(); } } ClientHikVision太长了,我贴出部分,这里基本都是初始化,连接设备都没问题 public class ClientHikVision { ExecutorService executor = Executors.newFixedThreadPool(5); FFmpegFrameGrabber grabber = null; FFmpegFrameRecorder recorder = null; PipedInputStream inputStream = new PipedInputStream(); PipedOutputStream outputStream = new PipedOutputStream(); String pushAddress = "rtsp://127.0.0.1:554/live/1"; public void initData(){ m_lPort= new IntByReference(-1); fRealDataCallBack = new FRealDataCallBack(); fExceptionCallBack = new FExceptionCallBack_Imp(); } public void initPipedStream(){ // inputStream = new PipedInputStream(); // outputStream = new PipedOutputStream(); try { inputStream.connect(outputStream); System.out.println("Piped设置连接成功"); } catch (IOException e) { throw new RuntimeException(e); } } public void clientInit() { if (hCNetSDK == null && playControl == null) { if (!CreateSDKInstance()) { System.out.println("Load SDK fail"); return; } if (!CreatePlayInstance()) { System.out.println("Load PlayCtrl fail"); return; } } //linux系统建议调用以下接口加载组件库 if (osSelect.isLinux()) { HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256); HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256); //这里是库的绝对路径,请根据实际情况修改,注意改路径必须有访问权限 String strPath1 = System.getProperty("user.dir") + "/lib/libcrypto.so.1.1"; String strPath2 = System.getProperty("user.dir") + "/lib/libssl.so.1.1"; System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length()); ptrByteArray1.write(); hCNetSDK.NET_DVR_SetSDKInitCfg(3, ptrByteArray1.getPointer()); System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length()); ptrByteArray2.write(); hCNetSDK.NET_DVR_SetSDKInitCfg(4, ptrByteArray2.getPointer()); String strPathCom = System.getProperty("user.dir") + "/lib/"; HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH(); System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length()); struComPath.write(); hCNetSDK.NET_DVR_SetSDKInitCfg(2, struComPath.getPointer()); } boolean initSuc = hCNetSDK.NET_DVR_Init(); if (!initSuc) { throw new CommonException(9001, "初始化失败"); } if (fExceptionCallBack == null) { fExceptionCallBack = new FExceptionCallBack_Imp(); } Pointer pUser = null; if (!hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, 0, fExceptionCallBack, pUser)) { return; } System.out.println("设置告警回调成功"); hCNetSDK.NET_DVR_SetLogToFile(3, "./sdklog", false); register(); } public void register() { //注册之前先注销已注册的用户,预览情况下不可注销 if (bRealPlay) { throw new CommonException(9001, "注册新用户请先停止当前预览!"); } if (lUserID > -1) { //先注销 hCNetSDK.NET_DVR_Logout_V30(lUserID); lUserID = -1; } //注册 m_sDeviceIP = EquipmentConstants.IP;//设备ip地址 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30(); int iPort = EquipmentConstants.PORT; lUserID = hCNetSDK.NET_DVR_Login_V30(m_sDeviceIP, (short) iPort, EquipmentConstants.ACCOUNT, EquipmentConstants.PSW, m_strDeviceInfo); long userID = lUserID; if (userID == -1) { m_sDeviceIP = "";//登录未成功,IP置为空 int error; error = hCNetSDK.NET_DVR_GetLastError(); throw new CommonException(9001, "注册失败,错误码:" + error); } else { initData(); } } public void action(){ if (lUserID == -1) { throw new CommonException(9001,"请先注册"); } //如果预览窗口没打开,不在预览 if (bRealPlay == false) { //获取窗口句柄 // W32API.HWND hwnd = new W32API.HWND(Native.getComponentPointer(panelRealplay)); //获取通道号 int iChannelNum = 1;//通道号 // m_strClientInfo = new HCNetSDK.NET_DVR_CLIENTINFO(); // m_strClientInfo.lChannel = new NativeLong(iChannelNum); HCNetSDK.NET_DVR_PREVIEWINFO strClientInfo = new HCNetSDK.NET_DVR_PREVIEWINFO(); strClientInfo.read(); // strClientInfo.hPlayWnd = null; //窗口句柄,从回调取流不显示一般设置为空 strClientInfo.lChannel = iChannelNum; //通道号 strClientInfo.dwStreamType=0; //0-主码流,1-子码流,2-三码流,3-虚拟码流,以此类推 strClientInfo.dwLinkMode=0; //连接方式:0- TCP方式,1- UDP方式,2- 多播方式,3- RTP方式,4- RTP/RTSP,5- RTP/HTTP,6- HRUDP(可靠传输) ,7- RTSP/HTTPS,8- NPQ strClientInfo.bBlocked=1; //0- 非阻塞取流,1- 阻塞取流 //在此判断是否回调预览,0,不回调 1 回调 //回调------------ strClientInfo.hPlayWnd = null; strClientInfo.write(); lPreviewHandle = hCNetSDK.NET_DVR_RealPlay_V40(lUserID, strClientInfo, fRealDataCallBack, null); if (lPreviewHandle 0) { long offset = 0; ByteBuffer buffers = pBuffer.getPointer().getByteBuffer(offset, dwBufSize); byte[] bytes = new byte[dwBufSize]; buffers.rewind(); buffers.get(bytes); System.out.println(Arrays.toString(bytes)); executor.execute(() -> { push(bytes,dwBufSize); }); // if (!playControl.PlayM4_InputData(m_lPort.getValue(), pBuffer, dwBufSize)) //输入流数据 // { // break; // } } } } } "image.png" (https://wmprod.oss-cn-shanghai.aliyuncs.com/c/user/20241008/fc6cf5d6aada71bdde97823704559a62.png) 上面的数据流写入到管道里,后面代码我不知道写的对不对,走了一个handle方法,grabber = new FFmpegFrameGrabber(inputStream,0),这里应该是消费管道中的数据流。这里用的ZLMediaKit做流媒体服务,我已经编译好启动了,但是不知道该怎么用,这个pushAddress地址我不知道写的对不对。里面的grabber.startUnsafe()方法每次调用都会阻塞,本来是grabber.start()方法的,两种方式都会阻塞, public void push(byte[] data, int size) { try { outputStream.write(data, 0, size); handle(); } catch (IOException | InterruptedException e) { throw new RuntimeException(e); } } public void handle() throws InterruptedException, IOException { System.out.println("-----开始处理流数据-----"); grabber = new FFmpegFrameGrabber(inputStream,0); grabber.setOption("rtsp_transport", "tcp"); grabber.setOption("stimeout", "2000000"); grabber.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); grabber.setVideoCodec(avcodec.AV_CODEC_ID_H264); grabber.setAudioStream(Integer.MIN_VALUE); grabber.setFormat("mpeg"); long stime = System.currentTimeMillis(); System.out.println("------1111111111------"); System.out.println(inputStream.available()); // 检测回调函数书否有数据流产生,防止avformat_open_input函数阻塞 do { Thread.sleep(100); if (System.currentTimeMillis() - stime > 2000) { System.out.println(("-----SDK回调无视频流产生------")); return; } }while (inputStream.available() 2000) { // System.out.println(("-----SDK回调无视频流产生------")); // return; // } // } while (inputStream.available() != 2048); // 只打印错误日志 avutil.av_log_set_level(avutil.AV_LOG_QUIET); FFmpegLogCallback.set(); System.out.println(grabber.toString()); grabber.startUnsafe(); System.out.println(("--------开始推送视频流---------")); recorder = new FFmpegFrameRecorder(pushAddress, grabber.getImageWidth(),grabber.getImageHeight(), grabber.getAudioChannels()); recorder.setInterleaved(true); // 画质参数 recorder.setVideoOption("crf", "28"); // H264编/解码器 recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); recorder.setVideoBitrate(grabber.getVideoBitrate()); // 封装flv格式 recorder.setFormat("flv"); // 视频帧率,最低保证25 recorder.setFrameRate(25); // 关键帧间隔 一般与帧率相同或者是帧率的两倍 recorder.setGopSize(50); // yuv420p recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); recorder.startUnsafe(); int count = 0; Frame frame; while (grabber.hasVideo() && (frame = grabber.grab()) != null) { count++; if (count % 100 == 0) { System.out.println("推送视频帧次数:"+count); } if (frame.samples != null) { System.out.println("检测到音频"); } recorder.record(frame); } if (grabber != null) { grabber.stop(); grabber.release(); } if (recorder != null) { recorder.stop(); recorder.release(); } } "image.png" (https://wmprod.oss-cn-shanghai.aliyuncs.com/c/user/20241008/dcd2298bdcd70c02ab62aa42df91c79a.png) System.out.println(grabber.toString());grabber.startUnsafe();这两行代码都走了,但是到这就停住阻塞不动了,麻烦大佬帮忙看下 "image.png" (https://wmprod.oss-cn-shanghai.aliyuncs.com/c/user/20241008/b6e39c05836a153d1fcf7c6b3d30e584.png) 参考资料 转: "大华、海康SDK对接,使用javacv+流媒体服务实现实时播放和回放" (https://link.segmentfault.com/?enc=oXk6caaYMGP8K7HN41C3CQ%3D%3D.aKLszW98wxtVdPRtJLDXLEX45Cp7wJ4SO6kn%2BGVA5DcBoMTW%2B834FImmfdmME4WNJWaB%2FaBfeBj8OG3veWKGeQ%3D%3D) "JavaCV中FFmpegFrameGrabber调用start()方法时出现阻塞的解决办法" (https://link.segmentfault.com/?enc=xx%2F97Pvf%2FIdUfjeIsiARww%3D%3D.yvzRtih7Gztwm69J7kZwPjRqqAzUUFj29kdit7OrcinEp051yA8LSfqn0yXD%2BjOL8BjzqIflzpaceFAsrqKmEgriJFv6XCvF6TObY%2BIxwNBSPCkAVdyqREvJo%2Fr29Fsl7sCB3e%2B9gBqfcswenirjI4amicp5bVZ48yfOTDHwpZEDAmJVL5i8PRNcXan3soSc9Wicd87PCmTDn2Ir5zJ1h7Nt%2BbYyBt6nGWj8drA902ghvnKwNxjhTZNpSsPYq5r0AyHOjWmSUf4Zs2mzDm7CVG7onAMLjJD6KQommQt%2B4Yho0JXpxObiNdLehIIz4KlcEvIZAJPIqAlUd2QuSfJ4%2BMHTZJ6b0qdftURyhanhBvE%3D)

0
1
0
浏览量184