IPC的集中调用方法(Java实现)

项目中涉及网络摄像头的相关内容,主要是视频流的解析送后端做各种处理,需要CS方式、BS方式等各种展现方式。

通常调用方法分为设备厂家SDK解析调用和RTSP协议读流解析调用两种大方法。

 

其中海康设备RTSP协议地址为:

rtsp://admin:12345@192.168.1.203:554/h265/ch1/sub/av_stream

主要关心参数为sub、main(区分主辅流)

云视通RTSP地址:

rtsp://192.168.1.203:8554/live1.265

主要关心参数为live0、live1(区分主辅流)  264、265区分协议 根据设备自定

还可以用ONVIF协议去discover,这里就不累赘了。

 

本片主要介绍RTSP协议的集中调用方法:

1、javacv 方式调用RTSP格式视频流  适合低并发CS模式

http://mvnrepository.com/artifact/org.bytedeco.javacpp-presets/opencv/3.2.0-1.3

package cn.xsw.rtsp;

import java.awt.Image;
import java.io.IOException;

import javax.swing.ImageIcon;

import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.OpenCVFrameConverter;

import cn.xsw.tools.Config;
import cn.xsw.view.ATvMain;

/**
 * 通过rstp方式获取视频流的帧
 *
 * @author xswsoft 2018年3月22日15:40:54
 */
public class RtspUtils implements Runnable {

	static Java2DFrameConverter java2dFrameConverter = new Java2DFrameConverter();
	static OpenCVFrameConverter.ToIplImage converterImage = new OpenCVFrameConverter.ToIplImage();
	public static boolean startCap = false;
	static int frameDate = 1000000;
	private static FFmpegFrameGrabber grabber;

	public static void main(String[] args) throws InterruptedException, IOException {
	}

	public RtspUtils() {
		super();
		init();
		// TODO 自动生成的构造函数存根
	}

	private static void init() {
		String rstpAdd = Config.getPropertyByName("view_video_source");
		grabber = new FFmpegFrameGrabber(rstpAdd);
		// grabber.setOption("rtsp_transport", "tcp");
		// grabber.setImageHeight(704);
		// grabber.setImageWidth(576);
	}

	private static void capFrameImg(FFmpegFrameGrabber grabber) {
		try {
			if (startCap == false) {
				grabber.start();
				startCap = true;
			}
			Frame frame = null;
			while ((frame = grabber.grabFrame()) != null) {

				ImageIcon imgc2 = new ImageIcon(java2dFrameConverter.convert(frame));

				imgc2.setImage(imgc2.getImage().getScaledInstance(ATvMain.lbl_video.getWidth(),
						ATvMain.lbl_video.getHeight(), Image.SCALE_DEFAULT));

				ATvMain.lbl_video.setIcon(imgc2);
			}
		} catch (FrameGrabber.Exception e) {
			e.printStackTrace();
			System.out.println("抓图报错!");
		}
	}

	@Override
	public void run() {
		// TODO 自动生成的方法存根
		capFrameImg(grabber);
	}
}

抓到图后咋处理就看自己了。

需要的jar包如下图:

优点:延迟低 <2s

2、webcam 方式   适合低并发CS模式

https://github.com/sarxos/webcam-capture

package cn.xsw.rtspview;

import java.awt.Dimension;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;

import javax.swing.JFrame;

import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamPanel;
import com.github.sarxos.webcam.WebcamResolution;

import cn.xsw.utils.Config;
import uk.co.caprica.vlcj.medialist.MediaListItem;

public class WebcamRtspExample {

	static {
		String name = "Big Buck Bunny";
		String rtsp = Config.getPropertyByName("view_video_source");
		Webcam.setDriver(new VlcjDriver(Arrays.asList(new MediaListItem(name, rtsp, new ArrayList<MediaListItem>()))));
	}

	public static void main(String[] args) throws InterruptedException, IOException {

		// 自定义分辨率
		Dimension[] nonStandardResolutions = new Dimension[] {
				// 640 * 480
				WebcamResolution.VGA.getSize(),
				// 960 * 640
				WebcamResolution.DVGA.getSize(),
				// WXGA1 1366 * 768
				WebcamResolution.WXGA1.getSize(),
				// 自定义分辨率
				new Dimension(2000, 1000) };

		Dimension dimension = WebcamResolution.WXGA1.getSize();

		Webcam webcam = Webcam.getWebcams().get(0);

		webcam.setCustomViewSizes(nonStandardResolutions);
		webcam.setViewSize(dimension);

		WebcamPanel panel = new WebcamPanel(webcam);

		JFrame window = new JFrame("Webcam Panel");
		window.add(panel);
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		window.pack();
		window.setVisible(true);
	}
}
package cn.xsw.rtspview;

import java.awt.Dimension;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ComponentColorModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.sarxos.webcam.WebcamDevice;
import com.github.sarxos.webcam.WebcamDevice.FPSSource;
import com.github.sarxos.webcam.WebcamException;
import com.github.sarxos.webcam.WebcamResolution;
import com.github.sarxos.webcam.util.OsUtils;
import com.sun.jna.Memory;

import uk.co.caprica.vlcj.medialist.MediaListItem;
import uk.co.caprica.vlcj.player.MediaPlayer;
import uk.co.caprica.vlcj.player.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.direct.BufferFormat;
import uk.co.caprica.vlcj.player.direct.BufferFormatCallback;
import uk.co.caprica.vlcj.player.direct.DirectMediaPlayer;
import uk.co.caprica.vlcj.player.direct.RenderCallback;
import uk.co.caprica.vlcj.player.direct.format.RV32BufferFormat;


/**
 * This is capture driver which uses <a href="http://caprica.github.io/vlcj/">vlcj</a> library to
 * access webcam hardware.
 *
 * @author Bartosz Firyn (SarXos)
 */
public class VlcjDevice implements WebcamDevice, BufferFormatCallback, RenderCallback, FPSSource {

	/**
	 * This class is to convert vlcj {@link Memory} to {@link BufferedImage}.
	 *
	 * @author Bartosz Firyn (sarxos)
	 */
	private static class Converter {

		/**
		 * Converters are cached and created on demand for every width-height tuple.
		 */
		private static final Map<String, Converter> CONVERTERS = new HashMap<String, Converter>();

		/**
		 * The buffer data type (buffer consist of 4 byte values for every pixel).
		 */
		final int dataType = DataBuffer.TYPE_BYTE;

		/**
		 * Number of bytes per pixel.
		 */
		final int pixelStride = 4;

		/**
		 * Number of bytes per line.
		 */
		final int scanlineStride;

		/**
		 * Band offsets for BGR components (B = 2, G = 1, R = 0).
		 */
		final int[] bgrBandOffsets = new int[] { 2, 1, 0 };

		/**
		 * Number of bits per component.
		 */
		final int[] bits = { 8, 8, 8 };

		/**
		 * Offset between pixels.
		 */
		final int[] offsets = new int[] { 0 };

		/**
		 * Transparency type (opaque since there is no transparency in the image).
		 */
		final int transparency = Transparency.OPAQUE;

		/**
		 * Color space, a standard default color space for the Internet - sRGB.
		 */
		final ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);

		/**
		 * Image sample model.
		 */
		final ComponentSampleModel sampleModel;

		/**
		 * Image color model.
		 */
		final ComponentColorModel colorModel = new ComponentColorModel(colorSpace, bits, false, false, transparency, dataType);

		private Converter(int width, int height) {
			this.scanlineStride = width * pixelStride;
			this.sampleModel = new ComponentSampleModel(dataType, width, height, pixelStride, scanlineStride, bgrBandOffsets);
		}

		/**
		 * Get memory converter for given width-height tuple.
		 *
		 * @param width the image width
		 * @param height the image height
		 * @return Converter
		 */
		public static Converter getConverter(int width, int height) {
			String key = key(width, height);
			Converter converter = CONVERTERS.get(key);
			if (converter == null) {
				converter = new Converter(width, height);
				CONVERTERS.put(key, converter);
			}
			return converter;
		}

		/**
		 * Use width and height to create map key.
		 *
		 * @param width the image width
		 * @param height the image height
		 * @return Map key
		 */
		private static String key(int width, int height) {
			return width + "x" + height;
		}

		/**
		 * Converts {@link Memory} into {@link BufferedImage}.
		 *
		 * @param buffers the {@link Memory} buffers
		 * @param format the image format
		 * @return {@link BufferedImage} created from {@link Memory}
		 */
		public BufferedImage convert(Memory[] buffers, BufferFormat format) {

			// sanity, check if buffers is not empty

			if (buffers.length == 0) {
				throw new RuntimeException("No memory elements found!");
			}

			// sanity check if buffer is not null

			final Memory memory = buffers[0];
			if (memory == null) {
				throw new RuntimeException("Null memory!");
			}

			// transfer bytes into array

			final byte[] bytes = new byte[scanlineStride * format.getHeight()];
			final byte[][] data = new byte[][] { bytes };

			memory
				.getByteBuffer(0, memory.size())
				.get(bytes);

			// create image

			DataBufferByte dataBuffer = new DataBufferByte(data, bytes.length, offsets);
			WritableRaster raster = Raster.createWritableRaster(sampleModel, dataBuffer, null);
			BufferedImage image = new BufferedImage(colorModel, raster, false, null);

			// flush reconstructable resources to free memory

			image.flush();

			// return image

			return image;
		}
	}

	/**
	 * Logger.
	 */
	private static final Logger LOG = LoggerFactory.getLogger(VlcjDevice.class);

	/**
	 * Artificial view sizes. The vlcj is not able to detect resolutions supported by the webcam. If
	 * you would like to detect resolutions and have high-quality with good performance images
	 * streaming, you should rather use gstreamer or v4lvj capture drivers.
	 */
	private final static Dimension[] RESOLUTIONS = new Dimension[] {
		WebcamResolution.QQVGA.getSize(),
		WebcamResolution.QVGA.getSize(),
		WebcamResolution.VGA.getSize(),
	};

	/**
	 * VLC args by Andrew Davison:<br>
	 * http://fivedots.coe.psu.ac.th/~ad/jg/nui025/snapsWithoutJMF.pdf
	 */
	private final static String[] VLC_ARGS = {
		"--no-video-title-show", // do not display title
		"--no-stats", // no stats
		"--no-sub-autodetect-file", // no subtitles
		"--no-snapshot-preview", // no snapshot previews
		"--live-caching=50", // reduce capture lag/latency
		"--quiet", // turn off warnings
	};

	/**
	 * Used to calculate FPS.
	 */
	private long t1 = -1;

	/**
	 * Used to calculate FPS.
	 */
	private long t2 = -1;

	/**
	 * Image exchange reference.
	 */
	private final AtomicReference<BufferedImage> imageRef = new AtomicReference<BufferedImage>();

	/**
	 * Current FPS.
	 */
	private final AtomicReference<Double> fps = new AtomicReference<Double>((double) 0);

	private final MediaListItem item;
	private final MediaListItem sub;

	/**
	 * Factory for media player instances.
	 */
	private MediaPlayerFactory factory;

	/**
	 * Specification for a media player that provides direct access to the video frame data.
	 */
	private DirectMediaPlayer player;

	/**
	 * Is in opening phase?
	 */
	private final AtomicBoolean opening = new AtomicBoolean();

	/**
	 * Is open?
	 */
	private final AtomicBoolean open = new AtomicBoolean();

	/**
	 * Is disposed?
	 */
	private final AtomicBoolean disposed = new AtomicBoolean();

	/**
	 * Current resolution.
	 */
	private Dimension resolution = null;

	protected VlcjDevice(MediaListItem item) {

		if (item == null) {
			throw new IllegalArgumentException("Media list item cannot be null!");
		}

		this.item = item;
		this.sub = item.subItems().isEmpty() ? item : item.subItems().get(0);

		LOG.trace("New device created {}", this);
	}

	/**
	 * Get capture device protocol. This will be:
	 * <ul>
	 * <li><code>dshow://</code> for Windows</li>
	 * <li><code>qtcapture://</code> for Mac</li>
	 * <li><code>v4l2://</code> for linux</li>
	 * </ul>
	 *
	 * @return Capture device protocol
	 * @throws WebcamException in case when there is no support for given operating system
	 */
	public String getCaptureDevice() {
		switch (OsUtils.getOS()) {
			case WIN:
				return "dshow://";
			case OSX:
				return "qtcapture://";
			case NIX:
				return "v4l2://";
			default:
				throw new WebcamException("Capture device not supported on " + OsUtils.getOS());
		}
	}

	public MediaListItem getMediaListItem() {
		return item;
	}

	public MediaListItem getMediaListItemSub() {
		return sub;
	}

	@Override
	public String getName() {
		return sub.name();
	}

	public String getMRL() {
		return sub.mrl();
	}

	public String getVDevice() {
		return getMRL().replace(getCaptureDevice(), "");
	}

	@Override
	public String toString() {
		return String.format("%s[%s (%s)]", getClass().getSimpleName(), getName(), getMRL());
	}

	@Override
	public Dimension[] getResolutions() {
		return RESOLUTIONS;
	}

	@Override
	public Dimension getResolution() {
		return resolution;
	}

	@Override
	public void setResolution(Dimension resolution) {
		this.resolution = resolution;
	}

	@Override
	public BufferedImage getImage() {

		if (!open.get()) {
			throw new WebcamException("Cannot get image, webcam device is not open");
		}

		BufferedImage image = null;

		// wait for image

		while ((image = imageRef.getAndSet(null)) == null) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				return null;
			}
		}

		return image;
	}

	@Override
	public synchronized void open() {

		if (disposed.get()) {
			LOG.warn("Cannot open device because it has been already disposed");
			return;
		}

		if (open.get()) {
			return;
		}

		if (!opening.compareAndSet(false, true)) {
			return;
		}

		factory = new MediaPlayerFactory(VLC_ARGS);
		player = factory.newDirectMediaPlayer(this, this);

		LOG.info("Opening webcam device");

		String[] options = null;

		switch (OsUtils.getOS()) {
			case WIN:
				LOG.debug("Open VLC device {}", getName());
				options = new String[] {
					":dshow-vdev=" + getName(),
					":dshow-size=" + resolution.width + "x" + resolution.height,
					":dshow-adev=none", // no audio device
				};
				break;
			case NIX:
				LOG.debug("Open VLC device {}", getVDevice());
				options = new String[] {
					":v4l2-vdev=" + getVDevice(),
					":v4l2-width=" + resolution.width,
					":v4l2-height=" + resolution.height,
					":v4l2-fps=30",
					":v4l2-adev=none", // no audio device
				};
				break;
			case OSX:
				LOG.debug("Open VLC device {}", getVDevice());
				options = new String[] {
					":qtcapture-vdev=" + getVDevice(),
					":qtcapture-width=" + resolution.width,
					":qtcapture-height=" + resolution.height,
					":qtcapture-adev=none", // no audio device
				};
				break;
		}

		player.startMedia(getMRL(), options);

		// wait for the first image

		long wait = 100; // ms
		int max = 100;
		int count = 0;

		while (imageRef.get() == null) {

			try {
				Thread.sleep(wait);
			} catch (InterruptedException e) {
				return;
			}

			if (count++ > max) {

				LOG.error("Unable to open in {} ms", wait * max);
				opening.set(false);

				return;
			}
		}

		open.set(true);
		opening.set(false);
	}

	@Override
	public synchronized void close() {

		LOG.info("Closing device {}", this);

		if (open.compareAndSet(true, false)) {
			player.stop();
		}
	}

	@Override
	public synchronized void dispose() {

		if (!disposed.compareAndSet(false, true)) {
			return;
		}

		LOG.debug("Release resources (player={}, factory={})", player, factory);

		player.release();
		factory.release();
	}

	@Override
	public boolean isOpen() {
		return open.get();
	}

	public MediaPlayer getPlayer() {
		return player;
	}

	@Override
	public BufferFormat getBufferFormat(int width, int height) {
		return new RV32BufferFormat(width, height);
	}

	@Override
	public void display(DirectMediaPlayer player, Memory[] buffers, BufferFormat format) {

		LOG.trace("Direct media player display invoked with format {}", format);

		// convert memory to image

		Converter converter = Converter.getConverter(format.getWidth(), format.getHeight());
		BufferedImage image = converter.convert(buffers, format);
		imageRef.set(image);

		// calculate fps

		if (t1 == -1 || t2 == -1) {
			t1 = System.currentTimeMillis();
			t2 = System.currentTimeMillis();
		}

		t1 = t2;
		t2 = System.currentTimeMillis();

		fps.set((4 * fps.get() + 1000 / (t2 - t1 + 1)) / 5);
	}

	@Override
	public double getFPS() {
		return fps.get();
	}
}
package cn.xsw.rtspview;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.sarxos.webcam.WebcamDevice;
import com.github.sarxos.webcam.WebcamDiscoverySupport;
import com.github.sarxos.webcam.WebcamDriver;
import com.github.sarxos.webcam.util.OsUtils;

import uk.co.caprica.vlcj.discovery.NativeDiscovery;
import uk.co.caprica.vlcj.medialist.MediaList;
import uk.co.caprica.vlcj.medialist.MediaListItem;
import uk.co.caprica.vlcj.player.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.discoverer.MediaDiscoverer;


/**
 * This is capture driver which uses <code>vlcj</code> library to gain access to the camera device.
 * The library can be found at:<br>
 * <br>
 * http://www.capricasoftware.co.uk/projects/vlcj/index.html
 *
 * @author Bartosz Firyn (SarXos)
 */
public class VlcjDriver implements WebcamDriver, WebcamDiscoverySupport {

	/**
	 * I'm the logger.
	 */
	private static final Logger LOG = LoggerFactory.getLogger(VlcjDriver.class);

	static {
		if ("true".equals(System.getProperty("webcam.debug"))) {
			System.setProperty("vlcj.log", "DEBUG");
		}
	}

	/**
	 * Are natives initialized.
	 */
	private static final AtomicBoolean initialized = new AtomicBoolean();

	/**
	 * Native library discoverer.
	 */
	private static NativeDiscovery nativeDiscovery;

	/**
	 * The scan interval.
	 */
	private long scanInterval = -1;

	/**
	 * Preconfigured media list items.
	 */
	private final List<MediaListItem> mediaListItems;

	public VlcjDriver() {
		this(null);
	}

	public VlcjDriver(List<MediaListItem> mediaListItems) {
		this.mediaListItems = mediaListItems;
		initialize();
	}

	/**
	 * Initialize natives.
	 */
	protected static void initialize() {
		initialize(true);
	}

	/**
	 * Initialize natives. If argument is true the natives are being loaded. In case of false this
	 * method do nothing. It's used mostly in unit tests.
	 *
	 * @param load the control to decide whether to load natives or ignore them
	 */
	protected static void initialize(boolean load) {
		if (load && initialized.compareAndSet(false, true)) {
			boolean nativeFound = getNativeDiscovery().discover();
			if (!nativeFound) {
				throw new IllegalStateException("The libvlc native library has not been found");
			}
			// Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class);
		}
	}

	@Override
	public List<WebcamDevice> getDevices() {

		LOG.debug("Searching devices");

		if (OsUtils.getOS() == OsUtils.WIN) {
			System.err.println("WARNING: VLCj does not support webcam devices discovery on Windows platform");
		}

		List<WebcamDevice> devices = new ArrayList<WebcamDevice>();

		if (mediaListItems != null) {

			for (MediaListItem item : mediaListItems) {
				devices.add(mediaListItemToDevice(item));
			}

		} else {

			MediaPlayerFactory mediaPlayerFactory = createMediaPlayerFactory();
			MediaDiscoverer videoMediaDiscoverer = mediaPlayerFactory.newVideoMediaDiscoverer();
			MediaList videoDeviceList = videoMediaDiscoverer.getMediaList();
			List<MediaListItem> videoDevices = videoDeviceList.items();

			for (MediaListItem item : videoDevices) {

				LOG.debug("Found item {}", item);

				devices.add(mediaListItemToDevice(item));
			}

			videoDeviceList.release();
			videoMediaDiscoverer.release();
			mediaPlayerFactory.release();
		}

		return devices;
	}

	/**
	 * Converts media list itemn into webcam device.
	 *
	 * @param item the item to be converted to webcam device instance
	 * @return Webcam device created from media list item
	 */
	protected WebcamDevice mediaListItemToDevice(MediaListItem item) {
		return new VlcjDevice(item);
	}

	/**
	 * Creates media player factory.
	 *
	 * @return New media player factory
	 */
	protected MediaPlayerFactory createMediaPlayerFactory() {
		return new MediaPlayerFactory();
	}

	@Override
	public boolean isThreadSafe() {
		return false;
	}

	@Override
	public String toString() {
		return getClass().getSimpleName();
	}

	@Override
	public long getScanInterval() {
		if (scanInterval <= 0) {
			return DEFAULT_SCAN_INTERVAL;
		}
		return scanInterval;
	}

	/**
	 * Set new scan interval. Value must be positive number. If negative or zero is used, then the
	 * corresponding getter will return default scan interval value.
	 *
	 * @param scanInterval the new scan interval in milliseconds
	 * @see VlcjDriver#DEFAULT_SCAN_INTERVAL
	 */
	public void setScanInterval(long scanInterval) {
		this.scanInterval = scanInterval;
	}

	@Override
	public boolean isScanPossible() {
		return OsUtils.getOS() != OsUtils.WIN;
	}

	protected static NativeDiscovery getNativeDiscovery() {
		if (nativeDiscovery == null) {
			nativeDiscovery = new NativeDiscovery();
		}
		return nativeDiscovery;
	}
}

jar包:

优点:简洁、跨平台好。 但延迟大3s左右

3、流媒体服务器接流转退RTMP、HLS等方式  适合BS   收费,便捷

https://www.linkingvision.com/

这个就看自己如何使用了,可以使用iframe嵌软件自带的页面,也可以自己写页面调用。

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

新思维软件

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值