通过java解码web前端直接预览海康威视摄像头

这篇具有很好参考价值的文章主要介绍了通过java解码web前端直接预览海康威视摄像头。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一:前言

        最近进行项目开发时遇到了需要前端直接调用摄像头,并直接进行播放的需求。原本计划通过海康威视官网的《WEB无插件开发包 V3.2》直接进行控制、交互,实现摄像头直接登录以及取流预览。但是前端人员现场驻场开发后反映各种兼容性问题频发,反正就是不能友好的进行预览播放。鉴于此我直接查询了官网上相关的sdk,然后选用了《设备网络SDK_Win64 V6.1.9.4_build20220412》进行开发java版本的转码工具。整体思路是在PS流中解析出H264的裸流然后通过websocket传给前端,前端基于wfs.js进行h264的裸流播放。

二:开发准备

下载开发SDK开发包,并先查看和熟悉sdk使用方法并先查看和熟悉sdk使用方法并先查看和熟悉sdk使用方法!(拜托不要一来就问源码呀,这就是我写的所有的代码了呀,甚至前端我都给你贴出来了,前端引入js、引入jquery-3.0.0.js不需要教吧。麻烦先在官网下载下来把项目运行起来啊,现在的做个开发的都这么浮夸的吗?)

海康开放平台sdk下载

下载wfs.js插件:GitHub - MarkRepo/wfs.js: use html5 video tag with MSE for raw h264 live streaming.

三:整体介绍

逻辑流转图:

由于博主太懒了,这里没有图。

3.1.后端逻辑:


①:java加载SDK包(dll)实现sdk加载和调用

②:调用sdk的NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo)接口实现登录。

③:调用sdk的NET_DVR_RealPlay_V40(userID, strClientInfo, fRealDataCallBack , null)接口实现预览取流。

④:在我们自定义的fRealDataCallBack回调函数中对取流数据进行解码,就是将数据进行截取以及转码操作,并将数据包进行存贮。

⑤:创建websocket类监听前端连接,区分摄像头后通过websocket进行实时推流。socket地址为'/wstest/{lUserID}'  其中lUserID是登录并预览成功后返回的lUserID!

主要代码展示:

package com.xunshi.hikangvision.Controller;

import com.xunshi.hikangvision.untils.PreverViewUntil;
import com.xunshi.hikangvision.vo.LoginVo;
import com.xunshi.hikangvision.vo.result.R;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/playvision")
public class HKController {
//    @Resource PreverViewUntil preverViewUntil;
    /**
     * 登录并开启预览
     * @param loginVo
     * @return
     */
    @PostMapping("/loginAndPlayView")
    public R<LoginVo> loginAndPlayView(@RequestBody LoginVo loginVo)
    {
       return R.buildOkData(PreverViewUntil.loginAndPlayView(loginVo));
    }

    /**
     * 退出预览&登录
     */
    //@ApiParam("loginAndPlayView接口中返回的lUserID")
    //@ApiParam("loginAndPlayView接口中返回的lPlayID")
    @GetMapping("/logoutPlayView")
    public R logoutPlayView(
            @RequestParam (value = "lUserID",required = true) String lUserID,
            @RequestParam (value = "lPlayID",required = false) String lPlayID)
    {
        if(null!=lPlayID)
        {
            PreverViewUntil.logoutPlayView(lUserID,lPlayID);
        }
        else
        {
            PreverViewUntil.logoutPlayView(lUserID);
        }
        return R.buildOk();
    }
    /**
     * 登录(判断是否在线),只登录不预览
     * ---支持批量登录
     * @param loginVos
     * @return
     */
    @PostMapping("/login")
    public R<List<LoginVo>> login(@RequestBody List<LoginVo> loginVos)
    {
        return R.buildOkData(PreverViewUntil.login(loginVos));
    }
    /**
     * 预览某个摄像头
     * @param loginVo
     * @return
     */
    @PostMapping("/playView")
    public R<LoginVo> playView(@RequestBody LoginVo loginVo)
    {
        return R.buildOkData(PreverViewUntil.playView(loginVo));
    }

    /**
     * 只关闭某个摄像头预览,但不退出登录
     * @param loginVo
     * @return
     */
    @PostMapping("/logoutPlayViewOnly")
    public R<LoginVo> logoutPlayViewOnly(@RequestBody LoginVo loginVo)
    {
        return R.buildOkData(PreverViewUntil.logoutPlayViewOnly(loginVo));
    }

}
package com.xunshi.hikangvision.untils;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.xunshi.hikangvision.untils.Common.osSelect;
import com.xunshi.hikangvision.vo.LoginVo;
import com.xunshi.hikangvision.vo.MyBlockingQueue;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

//@Component
public class PreverViewUntil {
    static boolean isInit = false;//是否初始化
    static HCNetSDK hCNetSDK = null;
    static PlayCtrl playControl = null;
    static PreverViewUntil.FExceptionCallBack_Imp fExceptionCallBack;//异常捕获回调

    /**
     * 异常信息捕获接受类
     */
    static class FExceptionCallBack_Imp implements HCNetSDK.FExceptionCallBack {
        public void invoke(int dwType, int lUserID, int lHandle, Pointer pUser) {
            switch(dwType)
            {
                case HCNetSDK.EXCEPTION_AUDIOEXCHANGE:		//语音对讲时网络异常
                    System.out.println("登录句柄:"+lUserID+"语音对讲异常");
                    break;
                case HCNetSDK.EXCEPTION_ALARM:			//报警上传时网络异常
                    System.out.println("登录句柄:"+lUserID+"报警上传时网络异常");
                    break;
                case HCNetSDK.EXCEPTION_PREVIEW:			//网络预览时异常
                    System.out.println("登录句柄:"+lUserID+"网络预览时异常");
                    //TODO: 关闭网络预览
                    break;
                case HCNetSDK.EXCEPTION_SERIAL:			//透明通道传输时异常
                    System.out.println("登录句柄:"+lUserID+"透明通道传输时异常");
                    //TODO: 关闭透明通道
                    break;
                case HCNetSDK.EXCEPTION_RECONNECT:		//预览时重连
                    System.out.println("登录句柄:"+lUserID+"预览时重连");
                    break;
                default:
                    System.out.println("登录句柄:"+lUserID+",异常事件类型:"+Integer.toHexString(dwType));
                    System.out.println("具体错误参照 SDK网络使用手册中:NET_DVR_SetExceptionCallBack_V30 方法中的异常定义!");
                    break;
            }
            return;
        }
    }
    /**
     * 动态库加载
     * @return
     */
    private static boolean CreateSDKInstance() {
        if (hCNetSDK == null) {
            synchronized (HCNetSDK.class) {
                String strDllPath = "";
                try {
                    if (osSelect.isWindows())
                        //win系统加载库路径
                        strDllPath = System.getProperty("user.dir") + "\\lib\\HCNetSDK.dll";
                    else if (osSelect.isLinux())
                        //Linux系统加载库路径
                        strDllPath = System.getProperty("user.dir") + "/lib/libhcnetsdk.so";

                    System.out.println("loadLibrary: " + strDllPath);
                    hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class);
                } catch (Exception ex) {
                    System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }
    /**
     * 播放库加载
     * @return
     */
    private static boolean CreatePlayInstance() {
        if (playControl == null) {
            synchronized (PlayCtrl.class) {
                String strPlayPath = "";
                try {
                    if (osSelect.isWindows())
                        //win系统加载库路径
                        strPlayPath = System.getProperty("user.dir") + "\\lib\\PlayCtrl.dll";
                    else if (osSelect.isLinux())
                        //Linux系统加载库路径
                        strPlayPath = System.getProperty("user.dir") + "/lib/libPlayCtrl.so";
                    playControl=(PlayCtrl) Native.loadLibrary(strPlayPath,PlayCtrl.class);

                } catch (Exception ex) {
                    System.out.println("loadLibrary: " + strPlayPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 类初始化时加载SDK
     * @PostConstruct 便于直接加载注入类
     */
    @PostConstruct
    public static void init() {
        System.out.println("加载海康威视SDK dll");
        System.out.println("初始化路径为:"+System.getProperty("user.dir") + "\\lib\\HCNetSDK.dll");
        if (hCNetSDK == null&&playControl==null) {
            if (!CreateSDKInstance()) {
                System.out.println("Load SDK fail");
                return;
            }
            if (!CreatePlayInstance()) {
                System.out.println("Load PlayCtrl fail");
                return;
            }
        }
        System.out.println("海康威视SDK dll加载成功");
        //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());
        }

        System.out.println("开始初始化海康威视Sdk");
        //SDK初始化,一个程序只需要调用一次
        boolean initSuc = hCNetSDK.NET_DVR_Init();
        if (initSuc != true) {
            System.out.println("初始化海康威视Sdk失败");
        }
        System.out.println("海康威视Sdk初始化成功!");
        System.out.println("开始设置异常消息回调");
        //异常消息回调
        if(fExceptionCallBack == null)
        {
            fExceptionCallBack = new PreverViewUntil.FExceptionCallBack_Imp();
        }
        Pointer pUser = null;
        if (!hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, 0, fExceptionCallBack, pUser)) {
            return ;
        }
        System.out.println("设置异常消息回调成功");
        System.out.println("开始设置启动SDK写日志");
        //启动SDK写日志
        hCNetSDK.NET_DVR_SetLogToFile(3, "..\\sdkLog\\", false);
        isInit = true;
    }

    //类销毁时清理sdk
    @PreDestroy
    public void clearSdk() {
        if (null!=hCNetSDK)
        {
            //SDK反初始化,释放资源,只需要退出时调用一次
            hCNetSDK.NET_DVR_Cleanup();
        }
    }




    /**
     * 摄像头登录(支持批量操作)
     * @param loginVos
     * @return
     */
    public static List<LoginVo> login(List<LoginVo> loginVos) {
        if(loginVos.size()<1) return loginVos;
        for (int i = 0; i < loginVos.size(); i++) {
            LoginVo loginVo = loginVos.get(i);
            if(!isInit)
            {
                init();
            }
            //如果已经登录,就先退出登陆
            String userIdByIp = MyBlockingQueue.findUserIdByIp(loginVo.getIp());
            if(null!=userIdByIp)
            {
                //自动判断是否在预览并退出
                PreverViewUntil.logoutPlayView(userIdByIp);
            }
            //登录设备,每一台设备分别登录; 登录句柄是唯一的,可以区分设备
            HCNetSDK.NET_DVR_USER_LOGIN_INFO m_strLoginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();//设备登录信息
            HCNetSDK.NET_DVR_DEVICEINFO_V40 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();//设备信息
            String m_sDeviceIP = "********";//设备ip地址
            m_sDeviceIP=loginVo.getIp();
            m_strLoginInfo.sDeviceAddress = new byte[HCNetSDK.NET_DVR_DEV_ADDRESS_MAX_LEN];
            System.arraycopy(m_sDeviceIP.getBytes(), 0, m_strLoginInfo.sDeviceAddress, 0, m_sDeviceIP.length());
            String m_sUsername = "*****";//设备用户名
            m_sUsername=loginVo.getUserName();
            m_strLoginInfo.sUserName = new byte[HCNetSDK.NET_DVR_LOGIN_USERNAME_MAX_LEN];
            System.arraycopy(m_sUsername.getBytes(), 0, m_strLoginInfo.sUserName, 0, m_sUsername.length());
            String m_sPassword = "******";//设备密码
            m_sPassword=loginVo.getPassword();
            m_strLoginInfo.sPassword = new byte[HCNetSDK.NET_DVR_LOGIN_PASSWD_MAX_LEN];
            System.arraycopy(m_sPassword.getBytes(), 0, m_strLoginInfo.sPassword, 0, m_sPassword.length());
            m_strLoginInfo.wPort = 8000; //SDK端口
            m_strLoginInfo.bUseAsynLogin = false; //是否异步登录:0- 否,1- 是
            m_strLoginInfo.write();

            String ipPortStr=loginVo.getIp()+":"+loginVo.getProt();
            System.out.println("开始登录:"+ipPortStr);
            int lUserID = hCNetSDK.NET_DVR_Login_V40(m_strLoginInfo, m_strDeviceInfo);
            if (lUserID == -1) {
                System.out.println(ipPortStr+"登录失败,错误码为" + hCNetSDK.NET_DVR_GetLastError());
                loginVo.setLoginStatus("0");
                loginVo.setLoginMessage("登录失败,错误码为" + hCNetSDK.NET_DVR_GetLastError());
                loginVo.setLUserID(null);
            } else {
                //判断DVR工作状态
//                HCNetSDK.NET_DVR_WORKSTATE_V30 devwork = new HCNetSDK.NET_DVR_WORKSTATE_V30();
//                boolean net_DVR_GetDVRWorkState_V30 = hCNetSDK.NET_DVR_GetDVRWorkState_V30(lUserID, devwork);
//                if (net_DVR_GetDVRWorkState_V30) {
//                    //设备的状态,0-正常,1-CPU占用率太高,超过85%,2-硬件错误,例如串口死掉
//                    if(devwork.dwDeviceStatic!=0)
//                    {
//
//                    }
//                }
//                else
//                {
//                    //未知错误:获取DVR工作状态失败
//                }
                //这里直接认为登陆成功就能预览吧。。
                String successStr=m_sDeviceIP + ":设备登录成功! " + "设备序列号:" +
                        new String(m_strDeviceInfo.struDeviceV30.sSerialNumber).trim();
                System.out.println(successStr);
                loginVo.setLoginMessage(successStr);
                loginVo.setLoginStatus("1");
                loginVo.setLUserID(lUserID);
                m_strDeviceInfo.read();
                //记录ip已经登录
                MyBlockingQueue.IPToUserIdMap.put(loginVo.getIp(),loginVo.getLUserID().toString());
            }
        }
        return loginVos;
    }

    /***
     * 实时预览某个摄像机
     * @param vo
     * @return
     */
    public static LoginVo playView(LoginVo vo)
    {
        //注释掉的代码也可以参考,去掉注释可以运行
        //VideoDemo.getIPChannelInfo(lUserID); //获取IP通道
        //int lDChannel = (int)m_strDeviceInfo.struDeviceV30.byStartDChan + lChannel -1;
        String ipPortStr=vo.getIp()+":"+vo.getProt();
        System.out.println("预览通道号: " + vo.getLDChannel());
        System.out.println("尝试预览连接:"+ipPortStr);
        VidePreView.RealPlay(vo.getLUserID(), vo.getLDChannel());//预览
        if(VidePreView.lPlayStatus)
        {
            vo.setPlsyStatus("1");
            vo.setPlsyMessage("预览请求成功!");
            vo.setLPlayID(VidePreView.lPlay);
            System.out.println("预览请求成功:"+vo);
            //创建数据体,等待视频流实时回调
            BlockingQueue bq = new ArrayBlockingQueue<>(10);
            MyBlockingQueue.bpMap.put(vo.getLUserID().toString(),bq);
            MyBlockingQueue.PlayToUserIdMap.put(vo.getLPlayID().toString(),vo.getLUserID().toString());
        }else
        {
            vo.setPlsyStatus("0");
            vo.setPlsyMessage("预览失败:"+VidePreView.lPlayErrorMassage);
            vo.setLPlayID(null);
        }
        return vo;
    }


    /**
     * 登录并播放某个摄像头视频
     */
    public static LoginVo loginAndPlayView(LoginVo loginVo) {
        if(!isInit)
        {
            init();
        }
        //如果已经登录,就先退出登陆
        String userIdByIp = MyBlockingQueue.findUserIdByIp(loginVo.getIp());
        if(null!=userIdByIp)
        {
            //自动判断是否在预览并退出
          PreverViewUntil.logoutPlayView(userIdByIp);
        }
        //登录
        List<LoginVo> loginVos = new ArrayList<>();
        loginVos.add(loginVo);
        loginVos = login(loginVos);
        String ipPortStr=loginVo.getIp()+":"+loginVo.getProt();
        if("1".equals(loginVo.getLoginStatus()))
        {
            //预览
            if("1".equals(loginVos.get(0).getLoginStatus()))
            {
                playView(loginVos.get(0));
            }
            else
            {
                System.out.println(ipPortStr+"----登陆成功,但是预览失败!");
                //登录并预览接口中,如果登陆成功但是预览失败,自动退出登录-清理数据体
                PreverViewUntil.logoutPlayView(loginVo.getLUserID().toString());
            }
        }
        else
        {
            System.out.println(ipPortStr+"----登陆失败!");
        }
        return loginVos.get(0);
    }

    /**
     * 某个摄像头退出登录
     * @param lUserID  登录句柄
     * @param lPlayID  预览句柄
     */
    public static void logoutPlayView(String lUserID,String lPlayID) {
        if(null!=hCNetSDK&&MyBlockingQueue.bpMap.containsKey(lUserID))
        {
            if (hCNetSDK.NET_DVR_StopRealPlay(Integer.valueOf(lPlayID)))
            {
                System.out.println("停止预览成功");
            }
            //退出程序时调用,每一台设备分别注销
            if (hCNetSDK.NET_DVR_Logout(Integer.valueOf(lUserID))) {
                System.out.println("注销登录成功");
            }
            //清理数据体
            MyBlockingQueue.clearByUserId(lUserID,true);
        }
    }

    /**
     * 某个摄像头退出登录,自动判断是否在预览并停止
     * @param lUserID  登录句柄
     */
    public static void logoutPlayView(String lUserID) {
        if(null!=hCNetSDK &&MyBlockingQueue.bpMap.containsKey(lUserID))
        {
            String playId = MyBlockingQueue.findPlayIdByUserId(lUserID);
            if(null!=playId)
            {
                if (hCNetSDK.NET_DVR_StopRealPlay(Integer.valueOf(playId)))
                {
                    System.out.println("停止预览成功");
                }
            }
            //退出程序时调用,注销登录
            if (hCNetSDK.NET_DVR_Logout(Integer.valueOf(lUserID))) {
                System.out.println("注销登录成功");
            }
            //清理数据体
            MyBlockingQueue.clearByUserId(lUserID,true);
        }
    }

    /**
     * 只关闭某个摄像头预览,但不退出登录
     * @param loginVo
     */
    public static LoginVo logoutPlayViewOnly(LoginVo loginVo) {
        if(null!=hCNetSDK)
        {
            if(null!=loginVo.getLPlayID())
            {
                if (hCNetSDK.NET_DVR_StopRealPlay(loginVo.getLPlayID()))
                {
                    System.out.println("停止预览成功");
                    loginVo.setLPlayID(null);
                    loginVo.setPlsyMessage("停止预览成功");
                    loginVo.setLoginStatus("0");
                }
                else
                {
                    //接口返回失败请调用NET_DVR_GetLastError获取错误码,通过错误码判断出错原因。
                    loginVo.setPlsyMessage("停止预览失败:接口返回失败请调用NET_DVR_GetLastError获取错误码,通过错误码判断出错原因。");
                }
            }
            //清理数据体
            MyBlockingQueue.clearByUserId(loginVo.getLUserID().toString(),false);
        }
        return loginVo;
    }
}
package com.xunshi.hikangvision.untils;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.ByteByReference;
import com.xunshi.hikangvision.vo.MyBlockingQueue;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import static com.xunshi.hikangvision.untils.PreverViewUntil.hCNetSDK;

public class VidePreView {

    static FRealDataCallBack1 fRealDataCallBack;//预览回调函数实现
    static VideoDemo.fPlayEScallback fPlayescallback; //裸码流回调函数
    public static int lPlay = -1;  //预览句柄
    public static boolean lPlayStatus = false;//预览是否成功
    public static String lPlayErrorMassage = "";//预览错误信息


    /**
     * 预览摄像头
     * @param userID 登录时返回的id
     * @param iChannelNo 通过哪个通道预览
     */
    public static void RealPlay(int userID, int iChannelNo) {
        if (userID == -1) {
            System.out.println("请先登录");
            lPlayStatus=false;
            lPlayErrorMassage="请先登录";
            return;
        }
        HCNetSDK.NET_DVR_PREVIEWINFO strClientInfo = new HCNetSDK.NET_DVR_PREVIEWINFO();
        strClientInfo.read();
        strClientInfo.hPlayWnd = null;  //窗口句柄,从回调取流不显示一般设置为空
        strClientInfo.lChannel = iChannelNo;  //通道号
        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;
        strClientInfo.write();

        //回调函数定义必须是全局的
        if (fRealDataCallBack == null) {
            fRealDataCallBack = new FRealDataCallBack1();
        }

        //开启预览
        lPlay = hCNetSDK.NET_DVR_RealPlay_V40(userID, strClientInfo, fRealDataCallBack , null);
        if (lPlay == -1) {
            int iErr = hCNetSDK.NET_DVR_GetLastError();
            System.out.println("取流失败" + iErr);
            lPlayStatus=false;
            lPlayErrorMassage="取流失败,错误码:" + iErr;
            return;
        }
        System.out.println("取流成功");
        lPlayStatus=true;
        return;
    }

    //预览回调
    static class FRealDataCallBack1 implements HCNetSDK.FRealDataCallBack_V30 {
        //预览回调   lRealHandle预览句柄回调
        public void invoke(int lRealHandle, int dwDataType, ByteByReference pBuffer, int dwBufSize, Pointer pUser) {
            //System.out.println("码流数据回调, 数据类型: " + dwDataType + ", 数据长度:" + dwBufSize);
            //播放库解码
            switch (dwDataType) {
                case HCNetSDK.NET_DVR_SYSHEAD: //系统头
                case HCNetSDK.NET_DVR_STREAMDATA:   //码流数据
                    if ((dwBufSize > 0)) {
                        //System.out.println("取流回调进行中.....");
                        byte[] outputData = pBuffer.getPointer().getByteArray(0, dwBufSize);
                        try {
                            writeESH264(outputData,lRealHandle);//将流写入对应的实体
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
            }
        }


        //多路视频的pes数据进行缓存,知道某一路视频的RTP包开头进入时进行取出返给前端
        Map<String,byte[]> EsBytesMap=new HashMap<>();
        /**
         * 提取H264的裸流写入文件
         * @param outputData
         * @throws IOException
         */
        public void writeESH264(final byte[] outputData,int lRealHandle) throws IOException {
            if (outputData.length <= 0) {
                return;
            }
            String playIdStr = String.valueOf(lRealHandle);
            byte[] allEsBytes = null;//当前这个通道的一个Rtp包数据
            if(!EsBytesMap.containsKey(playIdStr))
            {
                EsBytesMap.put(playIdStr,allEsBytes);
            }
            else
            {
                allEsBytes=EsBytesMap.get(playIdStr);
            }

            if ((outputData[0] & 0xff) == 0x00//
                    && (outputData[1] & 0xff) == 0x00//
                    && (outputData[2] & 0xff) == 0x01//
                    && (outputData[3] & 0xff) == 0xBA) {// RTP包开头
                // 一个完整的帧解析完成后将解析的数据放入BlockingQueue,websocket获取后发送给前端
                if (allEsBytes != null && allEsBytes.length > 0) {
                    //System.out.println("回调的lRealHandle:"+lRealHandle);
                    if(MyBlockingQueue.PlayToUserIdMap.containsKey(String.valueOf(lRealHandle)))
                    {
                        String userId = MyBlockingQueue.PlayToUserIdMap.get(String.valueOf(lRealHandle));
                        BlockingQueue blockingQueue = MyBlockingQueue.bpMap.get(userId);
                        //System.out.println("当前的lPlayID:"+lRealHandle);
                        //System.out.println("myBlockingQueue.bq is null?"+(null==blockingQueue));
                        try {
                            blockingQueue.put(allEsBytes);//将当前的某一路视频通道的上一个Rtp包放到队列中去
                            MyBlockingQueue.bpMap.put(userId,blockingQueue);
                            allEsBytes = null;
                            EsBytesMap.put(playIdStr,allEsBytes);//置空当前通道的RTP包,下次回调就是pes包进行取流追加
                        } 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;
                }
                EsBytesMap.put(playIdStr,allEsBytes);//当前视频通道的部分包数据进行缓存
            }
        }
    }
}
package com.xunshi.hikangvision.sevice;

import com.xunshi.hikangvision.untils.PreverViewUntil;
import com.xunshi.hikangvision.vo.MyBlockingQueue;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * 前后端交互的类实现消息的接收推送
 * @ServerEndpoint(value = "/wstest") 前端通过此URI和后端建立连接
 */
@Slf4j
@ServerEndpoint(value = "/wstest/{lUserID}")
@Component
public class OneWebSocket {

    /** 记录当前在线网页数量 */
    private static AtomicInteger onlineCount = new AtomicInteger(0);
    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(final Session session , @PathParam("lUserID") String lUserID) {
        onlineCount.addAndGet(1);
        System.out.println("当前已经登录用户句柄S:"+MyBlockingQueue.bpMap.keySet());
        log.info("有新连接加入sessionid:{},摄像头登录用户的句柄为:{} 当前在线socket(视频路数)数量:{}", session.getId(),lUserID, onlineCount);
        if(MyBlockingQueue.bpMap.containsKey(lUserID)){
            if(null==MyBlockingQueue.findPlayIdByUserId(lUserID))
            {
                System.out.println(String.format("警告:根据登录句柄%s,没有找到用户预览句柄",lUserID));
            }
            BlockingQueue blockingQueue = MyBlockingQueue.bpMap.get(lUserID);
            MyBlockingQueue.SessionToUserIdMap.put(session.getId(),lUserID);
            //这里按照逻辑来说这里绑定后就应该开启一个线层来干这个事情,查询了一下好像websocket就是多线程的直接干吧
            while (null!=session&&session.isOpen()&&null!=blockingQueue) {
                try {
                    byte[] esBytes = (byte[]) blockingQueue.take();
                    if(esBytes.length<1) {
                        System.out.println("取流失败,无内容");
                        continue;
                    }
                    ByteBuffer data = ByteBuffer.wrap(esBytes);
                    session.getBasicRemote().sendBinary(data);
                } catch (InterruptedException e) {
                    System.out.println("socket 数据发失败,错误信息为:"+e.getMessage());
                    return;
                } catch (IOException e) {
                    System.out.println("socket 数据发失败,错误信息为:"+e.getMessage());
                    return;
                }
            }
        }
        else
        {
            System.out.println("当前没有找到用户登录句柄,无法播放:"+lUserID);
        }
    }


    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(final Session session) {
        onlineCount.decrementAndGet(); // 在线数减1
        System.out.println(String.format("socket[%s]断开链接,查找并执行退出预览&登录",session.getId()));
        //执行退出操作
       if(MyBlockingQueue.SessionToUserIdMap.containsKey(session.getId()))
       {
           String userId = MyBlockingQueue.SessionToUserIdMap.get(session.getId());
           if(null!=userId)
           {
               System.out.println(String.format("找到正在登录id[%s]预览的的相关信息,执行停止预览并退出登录操作",userId));
               PreverViewUntil.logoutPlayView(userId);//执行退出预览操作
           }
       }
       else
       {
           System.out.println(String.format("没有找到该socket相关的登录预览信息,无需操作!"));
       }
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     * 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(final String message, final Session session) {
        log.info("服务端收到客户端[{}]的消息:{}", session.getId(), message);
    }

    @OnError
    public void onError(final Session session, final Throwable error) {
        System.out.println(String.format("socket[%s]发生错误,查找并执行退出预览&登录,错误消息是:"+error.getMessage(),session.getId()));
        //执行退出操作
        if(MyBlockingQueue.SessionToUserIdMap.containsKey(session.getId()))
        {
            String userId = MyBlockingQueue.SessionToUserIdMap.get(session.getId());
            if(null!=userId)
            {
                System.out.println(String.format("找到正在登录id[%s]预览的的相关信息,执行停止预览并退出登录操作",userId));
                PreverViewUntil.logoutPlayView(userId);//执行退出预览操作
            }
        }
        else
        {
            System.out.println(String.format("没有找到该socket相关的登录预览信息,无需操作!"));
        }
    }

    /**
     * 服务端发送消息给客户端
     */
    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);
        }
    }
}
package com.xunshi.hikangvision.vo;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicReference;

public class MyBlockingQueue {
//    static public BlockingQueue bq = new ArrayBlockingQueue<>(10);
//    public  String socketSessionId;   //前端和这个摄像头建立的websocketid
//    public  String lUserID="-1";  //摄像头登录句柄
//    public  String lPlayID="-1";    //摄像预览句柄

    static public Map<String,String> SessionToUserIdMap=new HashMap<>();
    static public Map<String,String> PlayToUserIdMap=new HashMap<>();
    static public Map<String,String> IPToUserIdMap=new HashMap<>();
    static public Map<String,BlockingQueue> bpMap=new HashMap<>();

    /**
     * 通过摄像头登录句柄进行数据清理
     * @param userId
     */
    static public void clearByUserId(String userId,boolean logout)
    {
        if(null==MyBlockingQueue.bpMap)
        {
            System.out.println("bpMap is null ");
            MyBlockingQueue.bpMap=new HashMap<>();
        }
        if(null==MyBlockingQueue.PlayToUserIdMap)
        {
            System.out.println("PlayToUserIdMap is null ");
            MyBlockingQueue.PlayToUserIdMap=new HashMap<>();
        }
        if(null==MyBlockingQueue.SessionToUserIdMap)
        {
            System.out.println("SessionToUserIdMap is null ");
            MyBlockingQueue.SessionToUserIdMap=new HashMap<>();
        }

        for (String key : MyBlockingQueue.PlayToUserIdMap.keySet())
        {
            String value = MyBlockingQueue.PlayToUserIdMap.get(key);
            if(value.equals(userId))
            {
                MyBlockingQueue.PlayToUserIdMap.remove(key);
                break;
            }
        }
        for (String key : MyBlockingQueue.SessionToUserIdMap.keySet())
        {
            String value = MyBlockingQueue.SessionToUserIdMap.get(key);
            if(value.equals(userId))
            {
                MyBlockingQueue.SessionToUserIdMap.remove(key);
                break;
            }
        }
        if(logout)
        {
            for (String key : MyBlockingQueue.IPToUserIdMap.keySet())
            {
                String value = MyBlockingQueue.IPToUserIdMap.get(key);
                if(value.equals(userId))
                {
                    MyBlockingQueue.IPToUserIdMap.remove(key);
                    break;
                }
            }
        }
    }

    /**
     * 通过ip查找是否正在登录或者预览
     * @param Ip
     */
    static public String findUserIdByIp(String Ip)
    {
        for (String key : MyBlockingQueue.IPToUserIdMap.keySet())
        {
            String value = MyBlockingQueue.IPToUserIdMap.get(key);
            if(key.equals(Ip))
            {
                return value;
            }
        }
        return null;
    }

    /**
     * 通过摄像头登录句柄查询当前用户是否正在预览
     * @param userId
     */
    static public String findPlayIdByUserId(String userId)
    {
        for (String key : MyBlockingQueue.PlayToUserIdMap.keySet())
        {
            String value = MyBlockingQueue.PlayToUserIdMap.get(key);
            if(value.equals(userId))
            {
                return key;
            }
        }
        return null;
    }

}
package com.xunshi.hikangvision.vo.result;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.springframework.http.HttpStatus;
import org.springframework.util.ObjectUtils;

import java.io.Serializable;


/**
 * 响应信息主体
 *
 * @param <T>
 * @author somewhere
 */
@ToString
@Accessors(chain = true)
@AllArgsConstructor
public class R<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    @Getter
    @Setter
    private int code = CommonConstants.SUCCESS;
    @Getter
    @Setter
    private HttpStatus httpStatus;
    @Getter
    @Setter
    private T data;
    private String[] messages = {};

    public R() {
        super();
    }
    public R(T data) {
        super();
        this.data = data;
    }
    public R(String... msg) {
        super();
        this.messages = msg;
    }
    public R(T data, String... msg) {
        super();
        this.data = data;
        this.messages = msg;
    }
    public R(T data, int code, String... msg) {
        super();
        this.data = data;
        this.code = code;
        this.messages = msg;
    }
    public R(Throwable e) {
        super();
        setMessage(e.getMessage());
        this.code = CommonConstants.FAIL;
    }
    public static R buildOk(String... messages) {
        return new R(messages);
    }
    public static <T> R buildOkData(T data, String... messages) {
        return new R(data, messages);
    }
    public static <T> R buildFailData(T data, String... messages) {
        return new R(data, CommonConstants.FAIL, messages);
    }
    public static <T> R buildFail(String... messages) {
        return new R(null, CommonConstants.FAIL, messages);
    }
    public static <T> R build(T data, int code, String... messages) {
        return new R(data, code, messages);
    }
    public static <T> R build(int code, String... messages) {
        return new R(null, code, messages);
    }
    public String getMessage() {
        return readMessages();
    }
    public void setMessage(String message) {
        addMessage(message);
    }
    public String readMessages() {
        StringBuilder sb = new StringBuilder();
        for (String message : messages) {
            sb.append(message);
        }
        return sb.toString();
    }
    public void addMessage(String message) {
        this.messages = ObjectUtils.addObjectToArray(messages, message);
    }
}

3.2.前端逻辑流程


①:准备好摄像头参数:ip、端口、预览通道、用户名、密码,请求后端接口‘/playvision/login’实现登录,登陆成功后端会返回loginStatus(登录状态:0-失败1-成功)、lUserID(登陆摄像头的id)

②:请求预览接口'/playvision/playView',将登录后返回的数据直接请求过来即可。请求成功后会返回plsyStatus(预览状态:0-失败1-成功)、lPlayID(预览成功的通道句柄id)

③:预览接口请求成功后,我们调用wfs.js插件进行实时预览。

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>h.264 To fmp4</title>
	<script src="js/jquery-3.0.0.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>
	<button id="loginAndPlayView">登录并预览</button>
	<div class="wfsjs">
		<video id="video1" muted="muted" controls="controls" style="width: 50%;height: 50%;" autoplay="autoplay"
			muted></video>
		<div class="ratio"></div>
	</div>

	<script>
		var mypath = "http://127.0.0.1:10086";

		/**
		 * 登录并预览按钮点击:先请求 登录+预览接口,然后返回将返回的lUserID拼接到socket地址后面,创建一个websocket。
		 * 然后创建wfs实列 ,执行wfs.attachWebsocket()和wfs.attachMedia(),最后将socket和vide标签绑定给创建的wfs即可
		 */
		$("#loginAndPlayView").click(function () {

			var loginVo = {
				"userName": "admin",    //摄像头登录账号
				"password": "****", //摄像头登录账号
				"ip": "192.**.0.**", //摄像头ip
				"prot": "8000"  //摄像头端口
			}
			$.ajax({
				type: 'post',
				url: mypath + "/playvision/loginAndPlayView",
				dataType: 'json',
				contentType: "application/json;charset=UTF-8",
				data: JSON.stringify(loginVo),
				xhrFields: { withCredentials: false },
				success: function (res) {
					console.log(res)
					if (res.code && res.data && res.data.loginStatus == "1") {
						var luserID = res.data.luserID;
						var lplayID = res.data.lplayID;
						if (Wfs.isSupported()) {
							var video1 = document.getElementById("video1");
							var wfs = new Wfs();
							var my_websocket_path = "ws://127.0.0.1:10086";
							var socket = new WebSocket(my_websocket_path + "/wstest/" + luserID);
							wfs.attachMedia(video1, luserID + "_" + lplayID);    //绑定video标签
							wfs.attachWebsocket(socket, luserID + "_" + lplayID)  //绑定socket
						}
					}
					else {
						alert("播放失败,错误信息:" + ((res.data && res.data.loginMessage) ? res.data.loginMessage : ""))
					}
				}
			});
		})
	</script>

</body>

</html>

④:注意摄像头参数配置需要配置编码为H.264
海康摄像头有前端的sdk吗,java,html,java,前端,摄像头实时预览

3.3 接口介绍


3.3.1登录并预览

通过`/playvision/loginAndPlayView`发起Post请求登陆摄像头并开启预览:

{
    "userName": 0,  //用户名
    "password": 1,  //密码
    "ip": "",       //摄像头所在ip
    "prot": 80,  //摄像头所在端口
    "lDChannel": 1   //使用预览通道
}

3.3.2退出预览&登录
通过`/playvision/logoutPlayView?lUserID=xx&lPlayID=xx`发起get请求退出摄像头的预览和登录


3.3.3批量登录(可用做判断摄像头是否在线)
通过`/playvision/login`发起Post请求登陆摄像头

[{
    "userName": 0,  //用户名
    "password": 1,  //密码
    "ip": "",       //摄像头所在ip
    "prot": 80,  //摄像头所在端口
    "lDChannel": 1   //使用预览通道
},
{
    "userName": 0,  //用户名
    "password": 1,  //密码
    "ip": "",       //摄像头所在ip
    "prot": 80,  //摄像头所在端口
    "lDChannel": 1   //使用预览通道
}
]


3.3.4 开启某个摄像头预览
通过`/playvision/playView`发起Post请求登陆摄像头

{
    "lUserID":1,  //登录接口返回的登录用户id(必填) 
    "userName": 0,  //用户名
    "password": 1,  //密码
    "ip": "",       //摄像头所在ip
    "prot": 80,  //摄像头所在端口
    "lDChannel": 1   //使用预览通道
}


3.3.5 只关闭某个摄像头预览,但不退出登录
通过`/playvision/logoutPlayViewOnly`发起Post请求登陆摄像头

{
    "lUserID":1,//登录接口返回的登录用户id(必填)
    "lPlayID":1,//预览接口返回的预览句柄id(必填)
    "userName": 0,  //用户名
    "password": 1,  //密码 
    "ip": "",       //摄像头所在ip 
    "prot": 80,  //摄像头所在端口
    "lDChannel": 1   //使用预览通道
}

3.3.6 TODO 待办
        代码封装、命名等比较仓促,没有很好很认真的封装,很多类、结构都只是开发探索时进行的编码,请读者深刻理解后自行进行封装和运用!!


3.3.7 常见错误定义:

EXCEPTION_EXCHANGE 0x8000 用户交互时异常(注册心跳超时,心跳间隔为2分钟) 
EXCEPTION_AUDIOEXCHANGE 0x8001 语音对讲异常 
EXCEPTION_ALARM 0x8002 报警异常 
EXCEPTION_PREVIEW 0x8003 网络预览异常 
EXCEPTION_SERIAL 0x8004 透明通道异常 
EXCEPTION_RECONNECT 0x8005 预览时重连 
EXCEPTION_ALARMRECONNECT 0x8006 报警时重连 
EXCEPTION_SERIALRECONNECT 0x8007 透明通道重连 
SERIAL_RECONNECTSUCCESS 0x8008 透明通道重连成功 
EXCEPTION_PLAYBACK 0x8010 回放异常 
EXCEPTION_DISKFMT 0x8011 硬盘格式化 
EXCEPTION_PASSIVEDECODE 0x8012 被动解码异常 
EXCEPTION_EMAILTEST 0x8013 邮件测试异常 
EXCEPTION_BACKUP 0x8014 备份异常 
PREVIEW_RECONNECTSUCCESS 0x8015 预览时重连成功 
ALARM_RECONNECTSUCCESS 0x8016 报警时重连成功 
RESUME_EXCHANGE 0x8017 用户交互恢复 
NETWORK_FLOWTEST_EXCEPTION 0x8018 网络流量检测异常 
EXCEPTION_PICPREVIEWRECONNECT 0x8019 图片预览重连 
PICPREVIEW_RECONNECTSUCCESS 0x8020 图片预览重连成功 
EXCEPTION_PICPREVIEW 0x8021 图片预览异常 
EXCEPTION_MAX_ALARM_INFO 0x8022 报警信息缓存已达上限 
EXCEPTION_LOST_ALARM 0x8023 报警丢失 
EXCEPTION_PASSIVETRANSRECONNECT 0x8024 被动转码重连 
PASSIVETRANS_RECONNECTSUCCESS 0x8025 被动转码重连成功 
EXCEPTION_PASSIVETRANS 0x8026 被动转码异常 
EXCEPTION_RELOGIN 0x8040 用户重登陆 
RELOGIN_SUCCESS 0x8041 用户重登陆成功 
EXCEPTION_PASSIVEDECODE_RECONNNECT 0x8042 被动解码重连 
EXCEPTION_CLUSTER_CS_ARMFAILED 0x8043 集群报警异常 
EXCEPTION_RELOGIN_FAILED 0x8044 重登陆失败,停止重登陆 
EXCEPTION_PREVIEW_RECONNECT_CLOSED 0x8045 关闭预览重连功能 
EXCEPTION_ALARM_RECONNECT_CLOSED 0x8046 关闭报警重连功能 
EXCEPTION_SERIAL_RECONNECT_CLOSED 0x8047 关闭透明通道重连功能 
EXCEPTION_PIC_RECONNECT_CLOSED 0x8048 关闭回显重连功能 
EXCEPTION_PASSIVE_DECODE_RECONNECT_CLOSED 0x8049 关闭被动解码重连功能 
EXCEPTION_PASSIVE_TRANS_RECONNECT_CLOSED 0x804a 关闭被动转码重连功能

3.4 demo代码:

HaiKangVisionTool: 通过HTTP进行控制、交互,实现摄像头直接ip登录以及取流、转码前端通过websocket直接预览的功能。文章来源地址https://www.toymoban.com/news/detail-789596.html

到了这里,关于通过java解码web前端直接预览海康威视摄像头的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 解决海康威视监控安装插件后依然预览不了

    故障表现: 多次重装插件依然浏览不了监控画面,一直显示以下图片信息,提示安装插件 原因: 监控探头版本老旧,画面不能在新版浏览器上播放,两者不能兼容 解决办法: 1.IE浏览器 点开设置,找到“兼容性视图设置” 将监控画面网址添加入框中,点击确定,再点关闭

    2024年02月16日
    浏览(32)
  • vue3实现海康威视根据海康插件进行监控实时预览和回放功能

    因为我的文章已经写过基于vue实现海康web插件进行视频播放开箱即用文章,这个文章是利用 vite+vue3+js 进行编写的,大致内容跟vue2一样,拿过去能直接用。 至于我为什么要用js而不用ts,因为海康提供的三个脚本为js语言的,ts尝试过一次,我道行太浅,没搞明白。 这些代码是

    2024年02月05日
    浏览(56)
  • vue2实现海康威视根据海康插件进行监控实时预览和回放功能,全套代码,开箱即用。

     这是一套拿到手就能直接用的根据海康提供的摄像机节点实时预览和回放的全步骤代码,开箱即用。  我的是基于vue2写的,vue3可以看我下一篇文章。 很多人在开发vue项目的时候,不知道怎么去开发视频实时预览和回放功能,然后一直查文档,再去看别人写的项目,就是无

    2023年04月15日
    浏览(53)
  • Python海康威视SDK实现实时预览:快速构建高效视频监控系统

    Python海康威视SDK实现实时预览:快速构建高效视频监控系统 在当今社会,安全问题越来越受到人们的关注,越来越多的企业和机构开始建设视频监控系统。而Python作为一种高效、易用的编程语言,已经成为了许多开发人员的首选。本文将介绍如何使用Python海康威视SDK来实现实

    2024年02月14日
    浏览(36)
  • web前端在vue中通过海康插件嵌入视频,实现实时预览以及视频回放功能

      首先第一步,在海康官网下海康视频插件下载到电脑中海康开放平台    然后新建一个组件,下面我直接把我封装好的组件代码拿出来,重要的地方我在代码中添加了注释   以上是封装的组件,下面是调用的方法   

    2024年02月03日
    浏览(36)
  • web实时预览功能开发 java 海康sdk nvr

    目录 1.实时视频流解决方案 2.步骤 1.搭建rtmp+flv服务器 2.java预览demo 3.实时预览 1.配置海康sdk库文件 2.修改FPREVIEW_NEWLINK_CB代码,推流 3.修改FPREVIEW_DATA_CB代码,取流 4.javacv的推流 3.部分代码 1.启动项目初始化cms,stream的代码 2.cms代码 3.stream代码 1.前端调用后台接口, 2.后台接口

    2024年02月16日
    浏览(27)
  • 海康威视摄像头二次开发_云台控制_视频画面实时预览(基于Qt实现)

    需求:需要在公司的产品里集成海康威视摄像头的SDK,用于控制海康威视的摄像头。 拍照抓图、视频录制、云台控制、视频实时预览等等功能。 开发环境: windows-X64(系统) + Qt5.12.6(Qt版本) + MSVC2017_X64(使用的编译器) 海康威视提供了 设备网络SDK ,设备网络SDK是基于设备私有网

    2024年02月13日
    浏览(36)
  • vue+海康威视视频web插件开发

    下载地址:海康威视官网 下载页面 文件解压后的目录 运行bin文件下的VideoWebPlugin.exe demo/demo_window_integration.html 包含了插件所有功能的,可参照此demo来开发、验证功能、排查问题 demo/demo_window_simple_playback.html.html  视频回放,可在此基础上二次开发 demo/demo_window_simple_preview.ht

    2023年04月08日
    浏览(64)
  • vue+js+海康web开发包接入海康威视摄像头

    一、登录海康开放平台下载web开发包,下载需要先登录海康账号,没有的需先注册一个。 海康开放平台web开发包下载地址:https://open.hikvision.com/download/5cda567cf47ae80dd41a54b3?type=10id=4c945d18fa5f49638ce517ec32e24e24 二、将web开发包引入vue项目 下载后解压的包目录如下: 将把webs下的整个

    2024年02月02日
    浏览(41)
  • 海康威视网络摄像头通过浏览器网页的配置流程

    一、登录 输入网络摄像机IP地址,显示登录窗口,输入用户名和密码后,点击登录。如果是新设备,需要先激活设备,设置登录密码。(Edge浏览器如何访问海康设备?) 二、界面介绍 登入界面后,会显示预览,回放,图片,配置。登陆后界面右上角会显示用户名和注销标签

    2024年02月08日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包