精华内容
下载资源
问答
  • 本地测试环境是电脑网口直接连接了一台摄像头,保证本地能打开摄像头的设置页面。 项目结构: demo框架采用springboot,直接运行DemoApplication类就行。 实现方式有两种 第一个方式是,使用海康官方的web...

    本地测试环境是电脑网口直接连接了一台摄像头,保证本地能打开摄像头的设置页面。

    项目结构:

    demo框架采用springboot,直接运行DemoApplication类就行。完整代码已上传。

     

    实现方式有两种

    第一个方式是,使用海康官方的web3.0,项目启动后直接用ie打开 http://localhost:8899/hk

    这个方式需要安装项目下的resources/static/hk/WebComponentsKit.exe

    这个exe安装文件是32位的,只能用32位的IE浏览器打开,我的测试版本是

    打开后的效果:

    点击登录,开始预览就可以预览了。

    回放模块的js代码改造过,那个开始时间和结束时间,和搜索出来的文件时间有区别,已改造好。

    现在回放和下载都是正常的,

    注意:点击开始回放后,回放的视频是以开始时间和结束时间来回放的。

    不能点击单个文件回放,如果要回放单个文件,请填写合适的开始时间和结束时间,以便只能搜索这个文件。

     

    第二种方式是

    参考地址:https://blog.csdn.net/qq_36720088/article/details/82893924?utm_source=distribute.pc_relevant.none-task

    1.使用海康威视的官方SDK访问摄像头,获取摄像头可用通道号,组装rtsp地址,获取摄像头的实时rtsp视频流。
    2.使用FFmpeg将rtsp流转换成rtmp流供网页显示。
    3.服务器搭建集成nginx-rtmp插件的nginx服务,将转换的rtmp流推送至nginx制定代理地址,实现外网访问。
    4.前端页面使用免费的前端H5插件video.js实现实时预览

    首先安装FFmpeg,下载地址:https://ffmpeg.zeranoe.com/builds/

    安装完成后,在项目中配置安装路径

     

    再把项目中的/resources/static/nginx-rtmp-win32-master.zip,解压到英文路径下,

    注意:路径有中文会导致启动失败

     

    项目启动成功后,访问直播地址 http://localhost:8899/vedio

    回放地址是:http://localhost:8899/vedioBack

    回放的功能是利用直播做的,重新播放的时候要刷新页面,

    回放的时间是写死的,请自行修改,时间格式:年月日T时分秒Z

    抓图和录像下载,请直接在浏览器访问地址测试

    localhost:8899/dev/catchPic

    localhost:8899/dev/downloadVideo

     

    完整项目代码已上传,

    下载地址:https://download.csdn.net/download/miao5371/12319142

     

    展开全文
  • 接上一章:一、JAVA调用海康威视SDK实现摄像头预览

    接上一章:一、JAVA调用海康威视SDK实现摄像头预览

    1. 添加摄像头信息输入框
    2. 添加视频控制按钮
    3. 添加截图功能

    代码:

    PreView.java

    package com.kx.hcws;
    
    import javax.swing.JFrame;
    import javax.swing.JPopupMenu;
    
    import com.kx.hcws.sdk.HCNetSDK;
    import com.kx.hcws.sdk.HCNetSDKManger;
    import com.kx.hcws.ui.Player;
    
    public class PreView {
    	// private static String ip;
    	// private static String username;
    	// private static String password;
    
    	public static void main(String[] args) {
    		// 确保一个漂亮的外观风格
    		JFrame.setDefaultLookAndFeelDecorated(true);
    		JPopupMenu.setDefaultLightWeightPopupEnabled(false);// 防止被播放窗口(AWT组件)覆盖
    
    		// 显示应用 GUI
    		javax.swing.SwingUtilities.invokeLater(new Runnable() {
    			@Override
    			public void run() {
    				// 初始化海康播放器
    				HCNetSDKManger.init();
    				HCNetSDK.INSTANCE.NET_DVR_Init();
    				HCNetSDK.INSTANCE.NET_DVR_SetConnectTime(5000, 5);
    				HCNetSDK.INSTANCE.NET_DVR_SetReconnect(1000, true);
    
    				/*
    				 * IP地址:摄像头IP地址。 用户名:摄像头登录用户名。 密码:摄像头验证码。 摄像头编号:可以自定义。
    				 * 
    				 * "192.168.2.18", "admin", "axjy123456", 8000, 1L
    				 */
    				new Player();
    			}
    		});
    	}
    }
    

    HcPlayerPanel.java

    package com.kx.hcws.ui;
    
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    
    import com.kx.hcws.sdk.HCNetSDK;
    import com.kx.hcws.sdk.HCNetSDK.FExceptionCallBack;
    import com.kx.hcws.sdk.HCNetSDKManger;
    import com.kx.hcws.sdk.PlayCtrl;
    import com.sun.jna.Native;
    import com.sun.jna.NativeLong;
    import com.sun.jna.Pointer;
    import com.sun.jna.examples.win32.W32API.HWND;
    import com.sun.jna.ptr.IntByReference;
    import com.sun.jna.ptr.NativeLongByReference;
    
    public class HcPlayerPanel extends JPanel {
    	private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(HcPlayerPanel.class);
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	// 播放控制
    	private static PlayCtrl playControl = PlayCtrl.INSTANCE;
    
    	private String m_sDeviceIP;
    	private String username;
    	private String password;
    	private int port;
    	private Long deviceId = 1L;
    
    	private long iChannelNum;
    
    	private boolean isplay = false;
    
    	// 用户参数
    	private HCNetSDK.NET_DVR_CLIENTINFO m_strClientInfo;
    	// 预览句柄
    	private NativeLong lPreviewHandle = new NativeLong(-1);
    	// 播放界面
    	public java.awt.Panel panelRealplay = new java.awt.Panel();
    	public javax.swing.JPanel jPanelRealplayArea = new javax.swing.JPanel();
    	// 设备指针
    	private NativeLongByReference devicePoint;
    	// 播放端口
    	private NativeLongByReference m_lPort = new NativeLongByReference(new NativeLong(-1));
    	// 异常回调
    	private FExceptionCallBack exceptionCallBack = new FExceptionCallBack() {
    		@Override
    		public void invoke(int dwType, NativeLong lUserID, NativeLong lHandle, Pointer pUser) {
    			NativeLong deviceid = pUser.getNativeLong(0);
    
    			System.out.println("预览异常:dwType=" + dwType + ",lUserID=" + lUserID + ",lHandle=" + lHandle + ",pUser="
    					+ deviceid.intValue());
    
    			// EXCEPTION_EXCHANGE = 0x8000;// 用户交互时异常
    			// EXCEPTION_AUDIOEXCHANGE = 0x8001;//语音对讲异常
    			// EXCEPTION_ALARM = 0x8002;// 报警异常
    			// EXCEPTION_PREVIEW = 0x8003;// 网络预览异常
    			// EXCEPTION_SERIAL = 0x8004;// 透明通道异常
    			// EXCEPTION_RECONNECT = 0x8005; // 预览时重连
    			// EXCEPTION_ALARMRECONNECT = 0x8006;//报警时重连
    			// EXCEPTION_SERIALRECONNECT = 0x8007;//透明通道重连
    			// EXCEPTION_PLAYBACK = 0x8010;// 回放异常
    			// EXCEPTION_DISKFMT = 0x8011;// 硬盘格式化
    			if (dwType == HCNetSDK.EXCEPTION_ALARM || dwType == HCNetSDK.EXCEPTION_RECONNECT
    					|| dwType == HCNetSDK.EXCEPTION_ALARMRECONNECT || dwType == HCNetSDK.EXCEPTION_SERIALRECONNECT
    					|| dwType == HCNetSDK.EXCEPTION_PLAYBACK || dwType == 32971 || dwType == 32776 || dwType == 32789
    					|| dwType == 32790 || dwType == 32791 || dwType == 32776 || dwType == 32793 || dwType == 32800
    					|| dwType == 32804 || dwType == 32805 || dwType == 32832 || dwType == 32833 || dwType == 32834) {
    				return;
    			}
    		}
    	};
    
    	public HcPlayerPanel() {
    		init();
    	}
    
    	/**
    	 * 开始,传入对应参数
    	 * 
    	 * @param m_sDeviceIP
    	 * @param username
    	 * @param password
    	 * @param port
    	 * @param deviceId
    	 */
    	public void start(String m_sDeviceIP, String username, String password, int port, Long deviceId) {
    		this.m_sDeviceIP = m_sDeviceIP;
    		this.username = username;
    		this.password = password;
    		this.port = port;
    		this.deviceId = deviceId;
    	}
    
    	/**
    	 * 初始化组件
    	 */
    	private void init() {
    		panelRealplay.setBackground(Color.BLACK);
    		jPanelRealplayArea.setBackground(Color.BLACK);
    		javax.swing.GroupLayout panelRealplayLayout = new javax.swing.GroupLayout(panelRealplay);
    		panelRealplay.setLayout(panelRealplayLayout);
    		javax.swing.GroupLayout jPanelRealplayAreaLayout = new javax.swing.GroupLayout(jPanelRealplayArea);
    		jPanelRealplayArea.setLayout(jPanelRealplayAreaLayout);
    		jPanelRealplayAreaLayout.setHorizontalGroup(
    				jPanelRealplayAreaLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(
    						panelRealplay, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE,
    						javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE));
    		jPanelRealplayAreaLayout.setVerticalGroup(jPanelRealplayAreaLayout
    				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(panelRealplay,
    						javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE));
    		devicePoint = new NativeLongByReference(new NativeLong(deviceId));// 设备编号
    
    		panelRealplay.setPreferredSize(new Dimension(getWidth(), getHeight()));
    
    		// 注册异常信息
    		HCNetSDKManger.hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, 0, exceptionCallBack, devicePoint.getPointer());
    	}
    
    	/**
    	 * 开始播放
    	 */
    	public void play() {
    		NativeLong lUserID = new NativeLong(-1);// 用户句柄
    		if (lUserID.longValue() > -1) {// 不注销
    			// 先注销
    			HCNetSDKManger.hCNetSDK.NET_DVR_Logout_V30(lUserID);
    			lUserID = new NativeLong(-1);
    		}
    		// 注册
    		HCNetSDK.NET_DVR_DEVICEINFO_V30 m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();
    		lUserID = HCNetSDKManger.hCNetSDK.NET_DVR_Login_V30(m_sDeviceIP, (short) port, username, password,
    				m_strDeviceInfo);
    		long userID = lUserID.longValue();
    		if (userID == -1) {
    			System.out.println(HCNetSDKManger.hCNetSDK.NET_DVR_GetLastError());
    			System.out.println("设备注册失败:" + m_sDeviceIP + "--" + username + "--" + password + "--" + port);
    			JOptionPane.showMessageDialog(this, "注册失败");
    			return;
    		} else {
    			// CreateDeviceTree();
    		}
    
    		if (lUserID == null || lUserID.intValue() == -1) {
    			logger.info("注册失败");
    			return;
    		}
    
    		panelRealplay.setPreferredSize(new Dimension(getWidth(), getHeight()));
    		removeAll();
    
    		add(jPanelRealplayArea, BorderLayout.CENTER);
    		revalidate();
    
    		// 获取窗口句柄
    		HWND hwnd = new HWND(Native.getComponentPointer(panelRealplay));
    		// 获取通道号
    
    		IntByReference ibrBytesReturned = new IntByReference(0);// 获取IP接入配置参数
    		boolean bRet = false;
    
    		HCNetSDK.NET_DVR_IPPARACFG m_strIpparaCfg = new HCNetSDK.NET_DVR_IPPARACFG();
    		m_strIpparaCfg.write();
    		Pointer lpIpParaConfig = m_strIpparaCfg.getPointer();
    		bRet = HCNetSDKManger.hCNetSDK.NET_DVR_GetDVRConfig(lUserID, HCNetSDK.NET_DVR_GET_IPPARACFG, new NativeLong(0),
    				lpIpParaConfig, m_strIpparaCfg.size(), ibrBytesReturned);
    		m_strIpparaCfg.read();
    
    		// 设备支持IP通道
    		String sChannelName = "";
    		if (!bRet) {
    			// 设备不支持,则表示没有IP通道
    			for (int iChannum = 0; iChannum < m_strDeviceInfo.byChanNum; iChannum++) {
    				sChannelName = "Camera" + (iChannum + m_strDeviceInfo.byStartChan);
    			}
    		} else {
    			// 设备支持IP通道
    			for (int iChannum = 0; iChannum < m_strDeviceInfo.byChanNum; iChannum++) {
    				if (m_strIpparaCfg.byAnalogChanEnable[iChannum] == 1) {
    					sChannelName = "Camera" + (iChannum + m_strDeviceInfo.byStartChan);
    				}
    			}
    			for (int iChannum = 0; iChannum < HCNetSDK.MAX_IP_CHANNEL; iChannum++)
    				if (m_strIpparaCfg.struIPChanInfo[iChannum].byEnable == 1) {
    					sChannelName = "IPCamera" + (iChannum + m_strDeviceInfo.byStartChan);
    				}
    		}
    		iChannelNum = -1;
    		if (sChannelName.charAt(0) == 'C') {// Camara开头表示模拟通道
    			// 子字符串中获取通道号
    			iChannelNum = Integer.parseInt(sChannelName.substring(6));
    		} else {
    			if (sChannelName.charAt(0) == 'I') {// IPCamara开头表示IP通道,子字符创中获取通道号,IP通道号要加32
    				iChannelNum = Integer.parseInt(sChannelName.substring(8)) + 32;
    			} else {
    				logger.info("通道号获取失败");
    				return;
    			}
    		}
    		if (iChannelNum == -1) {
    			logger.info("请选择要预览的通道");
    			return;
    		}
    
    		m_strClientInfo = new HCNetSDK.NET_DVR_CLIENTINFO();
    		m_strClientInfo.lChannel = new NativeLong(iChannelNum);
    		m_strClientInfo.hPlayWnd = hwnd;
    		lPreviewHandle = HCNetSDKManger.hCNetSDK.NET_DVR_RealPlay_V30(lUserID, m_strClientInfo, null, null, true);
    		long previewSucValue = lPreviewHandle.longValue();
    		// 预览失败时:
    		if (previewSucValue == -1) {
    			System.out.println("预览失败:" + HCNetSDKManger.hCNetSDK.NET_DVR_GetLastError());
    			return;
    		}
    		System.out.println("预览成功!");
    		validate();
    		isplay = true;
    	}
    
    	/**
    	 * 停止播放
    	 */
    	public void stop() {
    		logger.info("设备" + deviceId + "停止播放===================");
    		if (lPreviewHandle != null && lPreviewHandle.longValue() != -1) {
    			if (!HCNetSDKManger.hCNetSDK.NET_DVR_StopRealPlay(lPreviewHandle)) {
    				logger.info("设备" + deviceId + "停止播放失败");
    			}
    			if (m_lPort.getValue().intValue() != -1) {
    				if (!playControl.PlayM4_Stop(m_lPort.getValue())) {
    					logger.info("设备" + deviceId + "停止播放失败");
    				}
    				m_lPort.setValue(new NativeLong(-1));
    			}
    		}
    		panelRealplay.repaint();
    		isplay = false;
    	}
    
    	public boolean isIsplay() {
    		return isplay;
    	}
    
    	/**
    	 * 实现截图
    	 */
    	public void snapshot(String filepath) {
    		if (!HCNetSDKManger.hCNetSDK.NET_DVR_CapturePicture(lPreviewHandle, filepath)) {
    			JOptionPane.showMessageDialog(this, "设备截屏失败:" + HCNetSDKManger.hCNetSDK.NET_DVR_GetLastError());
    			System.out.println("设备截屏失败:" + HCNetSDKManger.hCNetSDK.NET_DVR_GetLastError());
    		}else{
    			JOptionPane.showMessageDialog(this, "截图成功!");
    		}
    	}
    }
    

    Player.java

    package com.kx.hcws.ui;
    
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.WindowEvent;
    import java.awt.event.WindowListener;
    import java.util.Date;
    
    import javax.swing.JButton;
    import javax.swing.JFileChooser;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JPasswordField;
    import javax.swing.JTextField;
    
    public class Player extends JFrame implements WindowListener {
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    
    	private HcPlayerPanel playerPanel;
    
    	private JTextField ipField;
    	private JTextField usernameField;
    	private JPasswordField pwdField;
    
    	public Player() {
    		setSize(1200, 600);
    		setResizable(true);
    		setTitle("设备预览");
    		setLocationRelativeTo(null);
    		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 关闭窗口时关闭系统
    
    		getContentPane().setLayout(new BorderLayout());
    
    		playerPanel = new HcPlayerPanel();
    		playerPanel.setBackground(Color.BLACK);
    		playerPanel.setPreferredSize(new Dimension(1000, 600));
    
    		getContentPane().add(playerPanel, BorderLayout.CENTER);
    
    		initCtrlPanel();
    
    		setVisible(true);
    	}
    
    	private void initCtrlPanel() {
    		JPanel content = new JPanel();
    		content.setLayout(new FlowLayout());
    
    		{// IP
    			JLabel jLabel = new JLabel("IP:");
    			jLabel.setPreferredSize(new Dimension(60, 30));
    			jLabel.setHorizontalTextPosition(JLabel.CENTER);
    			jLabel.setVerticalAlignment(JLabel.CENTER);
    			content.add(jLabel);
    
    			ipField = new JTextField();
    			ipField.setPreferredSize(new Dimension(130, 30));
    			content.add(ipField);
    		}
    
    		{// 用户名
    			JLabel jLabel = new JLabel("用户名:");
    			jLabel.setPreferredSize(new Dimension(60, 30));
    			jLabel.setHorizontalTextPosition(JLabel.CENTER);
    			jLabel.setVerticalAlignment(JLabel.CENTER);
    			content.add(jLabel);
    
    			usernameField = new JTextField("admin");
    			usernameField.setPreferredSize(new Dimension(130, 30));
    			content.add(usernameField);
    		}
    
    		{// 密码
    			JLabel jLabel = new JLabel("密码:");
    			jLabel.setPreferredSize(new Dimension(60, 30));
    			jLabel.setHorizontalTextPosition(JLabel.CENTER);
    			jLabel.setVerticalAlignment(JLabel.CENTER);
    			content.add(jLabel);
    
    			pwdField = new JPasswordField("");
    			pwdField.setPreferredSize(new Dimension(130, 30));
    			content.add(pwdField);
    		}
    
    		{// 按钮
    			JButton playBtn = new JButton("播放");
    			playBtn.setPreferredSize(new Dimension(150, 30));
    			playBtn.addActionListener(new ActionListener() {
    				@Override
    				public void actionPerformed(ActionEvent e) {
    					String m_sDeviceIP = ipField.getText();
    					if (m_sDeviceIP == null || "".equals(m_sDeviceIP)) {
    						JOptionPane.showMessageDialog(Player.this, "IP不能为空");
    						return;
    					}
    
    					String username = usernameField.getText();
    					if (username == null || "".equals(username)) {
    						JOptionPane.showMessageDialog(Player.this, "用户名不能为空");
    						return;
    					}
    
    					String password = pwdField.getText();
    					if (password == null || "".equals(password)) {
    						JOptionPane.showMessageDialog(Player.this, "密码不能为空");
    						return;
    					}
    
    					if (playerPanel.isIsplay()) {// 先停止
    						playerPanel.stop();
    					}
    					playerPanel.start(m_sDeviceIP, username, password, 8000, 1L);
    
    					new Thread(new Runnable() {
    						@Override
    						public void run() {
    							playerPanel.play();
    						}
    					}).start();
    				}
    			});
    			content.add(playBtn);
    
    			JButton imgBtn = new JButton("截图");
    			imgBtn.setPreferredSize(new Dimension(150, 30));
    			imgBtn.addActionListener(new ActionListener() {
    				@Override
    				public void actionPerformed(ActionEvent e) {
    					if (!playerPanel.isIsplay()) {// 先停止
    						JOptionPane.showMessageDialog(Player.this, "请先预览!");
    						return;
    					}
    					JFileChooser filechooser = new JFileChooser();// 创建文件选择器
    					filechooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
    					int returnVal = filechooser.showOpenDialog(Player.this);
    					if (returnVal == JFileChooser.APPROVE_OPTION) {
    						String file = filechooser.getSelectedFile().getAbsolutePath() + "\\" + new Date().getTime()
    								+ ".jpg";
    						playerPanel.snapshot(file);
    					}
    				}
    			});
    			content.add(imgBtn);
    		}
    
    		content.setPreferredSize(new Dimension(200, 600));
    
    		getContentPane().add(content, BorderLayout.WEST);
    	}
    
    	@Override
    	public void windowActivated(WindowEvent e) {
    
    	}
    
    	@Override
    	public void windowClosed(WindowEvent e) {
    	}
    
    	@Override
    	public void windowClosing(WindowEvent e) {
    		playerPanel.stop();
    	}
    
    	@Override
    	public void windowDeactivated(WindowEvent e) {
    
    	}
    
    	@Override
    	public void windowDeiconified(WindowEvent e) {
    
    	}
    
    	@Override
    	public void windowIconified(WindowEvent e) {
    
    	}
    
    	@Override
    	public void windowOpened(WindowEvent e) {
    
    	}
    }

    预览:

    源码:源码下载

    展开全文
  • 网上找的大多只有实时预览 自己写了一个 功能包括 实时预览 截图 录像 按指定时间、通道号回放硬盘录像机上录像 截图 等 附件包含所需dll 请解压后放入同一目录
  • Qt编写调用网络摄像头完成视频录制、播放、预览回放功能
  • 背景 由于在某监控安防厂工作,前段时间遇到了一个设备性能问题,就是设备...首先,给我们直观的感受是画面卡顿,但是一路预览并不卡段,只是随着预览路数上升时,才会造成画面的卡顿,通过查看,发现6路预览时,CPU...

    背景

    由于在某监控安防大厂工作,前端时间遇到了一个设备性能问题,就是设备6路预览时,画面卡单不连贯,体验极差。领导让我解决这个问题。经过几天的学习和探讨,问题是解决了。虽然其中涉及到的知识点并不多,但整个过程并不容易,故在此做出总结进行分享,希望能对遇到类似问题的朋友有所帮助。

    分析原因

    首先,给我们直观的感受是画面卡段,但是一路预览并不卡顿,随着预览路数增加,才会造成越来越卡顿的现象。通过分析,随着预览路数的增加,设备的CPU使用率也会上升,并且6路时,CPU达到90%以上。因此我的解决方向,放在了降低设备CPU使用率上。

    分析资源消耗

    一个设备中可能有许多进程,一个进程中可以有许多的线程,我们如何进行选择呢?这大概是许多人刚开始较为头疼的问题。我们可以使用下列命令查看设备各个线程的使用率。(一般的ps命令是经过裁减的,这个是我通过源码进行编译的,需要的朋友可以在我的资源里下载)

     ./ps -L c -e -o pid,tid,pcpu,cmd
    

    在这里插入图片描述
    值得注意的是,该命令得到的CPU使用率是设备从启动到当前的平均值,所以当时间变长时,该值会趋向于平缓。建议取10分钟的数据。通过这样的方式,我们可以直观的看到哪些线程消耗的资源较多,并且不合理。我们就可以去修改那些线程了。

    从何入手?

    当确认了需要修改的线程,很多人就会立刻去相应的线程代码中去看代码,希望从一行一行的代码中找到优化的点。可以是一种方式,但是我并不建议。因为这样没有侧重点,当然效率也就不会高。我建议先找到资源消耗的地方,再去重点走读代码,找到优化的地方。我们知道程序运行的过程中,存在两种状态,一个是应用态,一个是内核态。如果我们知道两种状态消耗的资源份额,就会知道重点去从哪个方向走读代码。

    linux 下一切皆文件

    秉承着该核心思想,通过在网上查询,发现proc文件系统的确给我们提供了这样的查看方式:

    awk '{print $1,$2,$14,$15}' /proc/PID/task/PPID/stat 
    

    通过上述的命令,我们可以分贝看到该线程的ID,线程名,用户态占用的时间,内核态占用的时间(强烈建议大家了解一下stat文件中各字段的意义,以后肯定会有用)。

    如果是用户态占用时间较多,说明该线程的时间消耗在算数运算或者是一些内存操作,数据库操作中;如果是内核态占用时间较多,说明是IO操作较多,比如文件操作,read,write等;

    举例:应用态较多

    在这里插入图片描述

    如图,我们得知时间主要消耗在应用态并且10分钟的CPU使用率大致在7%左右。而该线程的主要功能是定时查看数据库中注册用户是否过期,代码的整体框架大致如图:
    在这里插入图片描述

    其中MAX_REGIST_USER的值为1000,其实该代码的逻辑就存在很大的问题,因为无论什么情况下,该循环至少会执行3000次的数据库操作。这样是非常不合理的。后面经过我的修改,变成了以下的逻辑:
    在这里插入图片描述

    1.先获取数据库中过期的人数,并将人员用户名保存在数组中。(用户名为唯一标识)
    2.根据过期的人数以及用户名进行删除操作。
    这样简单的修改,就有极大的改善,原先7%的cpu使用率,现在只有0.1%左右。这其实就是内存换时间的思想。当然我这个肯定不是最优的方案。

    举例:内核态较多

    在这里插入图片描述

    该线程是我们预览的线程,可知cpu的消耗主要是集中在内核态。应该就是IO操作比较多了。由于代码逻辑较为复杂,篇幅较多等原因,我这里就不贴图了。

    分析代码逻辑,发现整个线程中只有一个writev接口,也就是说这有这一个IO操作。并且线程是将每一个rtp包weite一次,于是我就尝试将6个包发送一次,从而降低write的频率。果不其然,这样CPU就降下来了,从原先的7%降到了4.5%

    以上就是分别从内核态和应用态分析的思路,当然用户态和内核态如果都进行优化当然是最好的了。

    CPU降下来了,预览效果不达标

    通过上述的修改,设备在6路预览时,CPU使用率大致在80%左右。但是预览时,依旧会明显卡顿,难道是CPU高的原因?我心中怀疑了一下(当然,CPU继续往下降,预览是不会卡的了)。于是我就将前端设备的CPU使用率搞到了90%进行6路预览,惊奇的发现,前端设备6路预览并不卡,非常流畅。于是我的思考方向不在是降CPU使用率。

    线程间的调度策略和优先级

    在进行下一步的讲解前,我先简单介绍一下调度策略的相关内容。linux下一共有三种调度策略。
    SCHED_FIFO 先进先出实时调度策略
    SCHED_RR 轮转实时调度策略
    SCHED_OTHER 其他非实时调度策略
    每个调度策略都是有优先级的,实时类的大于分时类的。默认的配置是,实时优先级099,分时的优先级在100139之间。

    SHCED_FIFO

    对于FIFO类,有以下规则:
    除非在以下情况下,系统不会中断一个正在执行的FIFO线程:
    另一个具有更高优先级的FIFO线程就绪
    正在执行的FIFO线程因为等待一个事件(如I/O)而被阻塞
    正在执行的FIFO线程通过调用SCHED_yield原语放弃处理器
    当一个FIFO线程被中断后,它被放置在一个与优先级相关联的队列中
    当一个FIFO线程就绪,并且如果该线程的优先级比当前正在处理的线程拥有更高的优先级时,当前被执行的线程被抢占,具有更高优先级且就绪的FIFO线程
    开始执行,如果多个线程都具有更高的优先级,则选择等待时间最长的线程

    SCHED_RR

    对于RR类,每个线程都有一个时间量与之关联(就是我们常听到的时间片),当一个RR线程在它的时间量里执行结束之后,它被挂起,然后调度器选择一个具有相同或更高优先级的实时线程运行。
    在这里插入图片描述

    SCHED_FIFO:D->B->C->A

    SCHED_RR: D->D->B->C->B->C->A

    SCHED_OTHER

    对于SCHED_OTHER类,我们需要注意的是,它实际运行起来的优先级和时间片是动态变化的;

    1. 时间片的范围是10~200ms,一般而言,具有较高优先级的任务分配的时间片也比较大
    2. 动态优先级是静态优先级和执行行为的函数计算出来的,一般来说,大部分时间处于睡眠的线程拥有较高优先级

    简单了解了各个调度策略之后,我们进一步看一下我们的问题。于是我就通过下面的命令查看了各个线程的调度策略和优先级:

    awk '{print $1,$2,$40,$41}' /proc/PID/task/*/stat 
    

    结果发现线程的调度策略大部分都是 0 ,并且优先级都是0。仅有几个线程的调度策略是实时FIFO调度策略。我们上述说过分时调度算法(SCHED_OTHER)的优先级和时间片是动态变化的。并且还有FIFO线程可能来进行抢占,这当然会导致我们预览效果卡顿。于是我就将预览的线程改为了实时策略(RR),只需要在线程中添加如下代码即可:

     struct sched_param sp={0};
     int policy = SCHED_RR;
     sp.sched_priority = 60;
     if (0 == pthread_setschedparam(pthread_self(), policy, &sp)) {
        printf("IO Thread #%u using high-priority scheduler!", pthread_self());
     }
       else{
        printf("pthread_setschedparam fail,pthread_self() = %u,%d\n",pthread_self(),errno);
       }
    

    编译,烧录,运行。发现调度策略和优先级的确是修改成功了。预览效果也有所提高,但是仍然会有卡顿。

    思考数据源

    到了这里,我觉得预览线程应该已经获取到很高的cpu支配权限了,但是为什么仍然会卡呢。我于是想是不是数据源慢了?由于DSP向缓冲区放数据慢了,导致应用取不到数据,造成卡顿。于是和杨工商量了一下,让他把产生数据的线程设置为RR优先级为85,如下图:
    ···
    352 (Enc_drvStream) 85 2
    353 (DemuxStreamThr) 85 2
    ···
    结果得到了很大的改善,进本都是很流畅的,只是偶然会有几路卡顿。

    优化应用代码

    到了这一步,我觉得只有几路会偶然卡顿,应该就不是数据源的问题了,如果是数据源的问题,一般都会是6路一起卡顿。思考方向就在应用了,通过分析,将一些打印和sleep时间进行修改,基本就不会卡顿了。其中需要注意的是打印的代码,虽然我们代码中打印设置了打印等级,但是有些不必要的代码仍然会被执行,造成浪费;
    在这里插入图片描述

    如图,红色方框内就会被执行。

    最终在其他方面也进行一些修修改改,最终的效果还是比较满意的。基本的思路就是这样的。希望对大家有所帮助

    展开全文
  • 前段时间对接了萤石摄像头,在此做一次总结,总体思路是:把萤石摄像头绑定到萤石云平台上,利用云平台的api来获取到access_token等信息,最终拼接成一个url,放在一个iframe标签中即可。 提示:以下是本篇文章正文...


    前言

    前段时间对接了萤石摄像头,在此做一次总结,总体思路是:把萤石摄像头绑定到萤石云平台上,利用云平台的api来获取到access_token等信息,最终拼接成一个url,放在一个iframe标签中即可。


    提示:以下是本篇文章正文内容,案例可供参考

    一、在萤石云平台上注册账号并添加设备以及创建应用

    萤石云平台
    PC客户端下载
    在萤石云平台上进行账号注册和登录。
    在PC客户端中登录已经注册的账号以后进行设备添加,添加以后效果如下:我这里是几个摄像头挂在了录像机上面,所有就显示了一个设备,几个摄像头又被分在了不同的通道上。
    在这里插入图片描述
    在我的账号下我的应用中创建一个应用,后续调用平台的api需要用到。
    在这里插入图片描述

    在PC客户端里也可以对摄像头的一系列相关信息进行编辑,这里就不再详述。

    二、利用云平台的api获取到前端展示需要的相关信息

    获取accessToken接口文档
    获取用户下的直播地址列表
    视频参考地址如下
    下载ezuikit.js

    三、前端页面展示内容

    前端页面展示案例效果如下:在这里插入图片描述
    前端页面添加设备以后的展示效果如下:这里设备不在线,所有没法看到实时视频以及回放。
    在这里插入图片描述

    其中iframe的src为:src=“https://open.ys7.com/ezopen/h5/iframe_se?url=ezopen://open.ys7.com/F43268732/1.live&autoplay=1&audio=1&accessToken=at.ck3a0s9z4kgnfvva2xocucbh4twah1kf-99s18gqdat-1j0nwew-v6sm6jtbp&templete=2”
    其中url=ezopen://open.ys7.com/F43268732/1.live,"F43268732"为录像机的设备序列号,"1"为摄像头的通道号。
    最后直接把拼接的iframe放入到web端的html页面中即可。


    总结

    对接萤石摄像头主要是在萤石云平台的基础上对接的,差不多是平台完成了这个功能,而我这边只是利用了平台的这个工具而已,有很大的局限性,对摄像头更详细的信息并没有深入了解,还是停留在了使用的阶段,就此做一下记录。

    展开全文
  • 怎么启动预览到surfaceview略过,主要是在surfaceChanged或surfaceCreate添加一个预览回调 @Override public void surfaceChanged (SurfaceHolder holder, int format, int width, int height) ...
  • VC 实现摄像头采集回放的程序,也就是捕获视频内容,并预览回放出捕获的视频,同时程序还支持视频压缩、抓取单帧图像保存等功能。
  • 2.从海康官网下载了SDK及DEMO功能,选择回放下载功能模块,无论将录像的MP4文件放置在哪里,都搜索不到,原来查找录像文件是从nvr硬盘里查找并实现播放功能的; 3.直接调用播放库类,然后选择录像文件的路径即可...
  • 海康威视摄像头实时预览视频流保存到文件中 目前在开发海康威视sdk ,IPC设备,视频回调用的是官方提供的Demo中的(fRealDataCallBack ) 在最下面代码可以设置Thread.sleep()设置拍摄时长 注:本文为博主原创文章,未经...
  • 本工程有具体的demo ,QT 海康sdk 预览 回放 多线程 同时处理 多路 包含所有的库,不懂的可以私信我
  • 公司项目需要页面集成大华摄像头画面,并实现回放功能。经过咨询大华相关人员给出两种方式,一种是基于OCX插件的网页集成,另一种是基于大华webplugin网页插件的集成。 OCX插件需要与大华的DSS平台对接,公司没有...
  • 海康官方拿到的开发中间件。
  • 时下视频聊天几乎成了网吧老板们制胜的法宝,自己的软件嵌入视频通信方式又显得那么酷,而一个摄像头只需要百来块钱。本软件功能上可以实现视频采集、预览,选择压缩器(视频文件可是大得惊人!)进行压缩、解压,...
  • 预览 方式一 ( 由SDK实现解码显示 ) # include # include # include "Windows.h" # include "HCNetSDK.h" # include using namespace std ; typedef HWND ( WINAPI * ...
  • 环境准备 代码实现 效果预览
  • 前段时间对接了大华摄像头,在此做一次总结,总体思路是:把大华摄像头绑定到乐橙云平台上,利用云平台的api来获取到kitToken等信息,最终拼接成一个url,通过配置ImouPlayer,放在一个div中实现。 提示:以下是本...
  • 演示如何使用大华playSdk完成androi设备和大华产品的对接开发,包含预览回放,对讲,报警相关功能
  • 海康威视摄像头估计很多项目中都会遇到,而且在安防领域特别常见,那么最基础的功能就是预览视频流,更深一层可能还会回放视频,云台控制,录像等等,如果单单是预览视频流,大家其实不需要接入海康的SDK,只需要...
  • 大华技术部提供的Android版SDK,试用与摄像+录像机模式,。
  • 目的:因为公司需求,需要对接海康大华等硬盘录像机进行二次开发,想无插件在web中和手机端直接浏览监控和回放。 经历:经过本人亲自对接过海康和大华的sdk,得到的效果并不是很理想。网上收集了无数资料(毫不夸张...
  • 海康威视HK报警布防监听,获取设备能力集,解码器示例代码,回放下载,实时预览. 内含SDK、开发文档 及Demo示例,C++,C#,Java.
  • 海康摄像头 前端控件

    2018-09-01 18:05:10
    海康平台摄像头实时监控,视频播放,回放页面控件。支持摄像头角度调整 ,调焦距,紧急抓图,多窗口切换等功能
  • 莹石云(EZVIZ) 实时视频预览、录像回放、语音对讲插件地址:https://ext.dcloud.net.cn/plugin?id=2454
  • 我们有客户发现在局域网内部署EasyGBS,成功运行后,进入实时预览页面,大华的摄像头画面却一直显示黑屏。接下来为大家介绍下排查的步骤,供参考! 问题分析 1、首先,我们在视频页面检查下视频参数是否都正确。...
  • 海康威视视频监控web开发最新插件包(包含实时预览回放demo),插件支持谷歌浏览器
  • 1.工具准备 ... ...2. 实时预览FFmpeg命令格式 ffmpeg -rtsp_transport tcp -i rtsp://user:password@ip:port/Streaming/channels/101 -c copy -f flv rtmp://127.0.0.1:1935/live/mystream 参数解
  • 方案简介 网络摄像头监控视频低延迟一直是一个比较难以解决的问题,很多非音视频开发专业的技术人员,花费了大量精力开发出来的各种集成网络监控摄像头在浏览器Web网页实时...市面上监控摄像头实时预览平台分析 目前
  • 之前,做过基于QT的海康摄像头二次开发,集成了预览、抓图、手动录像等功能。 本次实现功能: 1、多窗口预览(支持1-16窗口切换) 2、拖拽预览 3、语音对讲 4、录像回放 5、自定义视频时间进度条控件 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,221
精华内容 488
关键字:

回放摄像头预览