Java opencv拉取网络摄像头视频流推送到流媒体服务器

Java opencv拉取网络摄像头视频流推送到流媒体服务器

  1. 新建maven项目,添加如下maven依赖,注意添加lombok的版本号。
	<dependency>
	       <groupId>org.bytedeco</groupId>
	       <artifactId>javacv-platform</artifactId>
	       <version>1.5.1</version>
    	</dependency>
	<dependency>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
	</dependency>
  1. 代码实现如下。封装好的可以直接使用。下面有测试的main方法。我这里是使用的是nginx作为流媒体服务器,关于流媒体服务器搭建网上有很多的资料。具体的实现方案可以使用源码编译安装nginx ,添加nginx-http-flv-module模块。
@Slf4j
public class ConvertVideoPakcet {


	private static final Map<String,ConvertVideoPakcet> convertVideoPakcets = new HashMap<>();

	private FFmpegFrameGrabber grabber = null;
	private FFmpegFrameRecorder record = null;
	private int width = -1, height = -1;

	// 视频参数
	private int audiocodecid;
	private int codecid;
	private double framerate;// 帧率
	private int bitrate;// 比特率

	// 音频参数
	private int audioChannels;
	private int audioBitrate;
	private int sampleRate;

	//控制程序循环
	private Boolean flag = true;


	private static ConvertVideoPakcet get(String deviceId){
		return convertVideoPakcets.get(deviceId);
	}

	public static Boolean start(String deviceId,String formUrl,String toUrl){

		if(null != get(deviceId)) return true;

		final ConvertVideoPakcet convertVideoPakcet = new ConvertVideoPakcet();
		convertVideoPakcets.put(deviceId,convertVideoPakcet);

		new Thread(new Runnable() {
			@Override
			public void run() {
				log.info("start device");
				try {
					convertVideoPakcet.rtsp(formUrl).rtmp(toUrl).start();
				} catch (IOException e) {
					log.error("start dvice error,{}",e);
				}
			}
		}).start();

		log.info("start device finish!");
		return true;
	}

	/**
	 * 停止当前直播
	 * @param id
	 * @return
	 */
	public static Boolean stop(String id){
		log.info("stop device ,{}",id);
		ConvertVideoPakcet convertVideoPakcet = get(id);

		if(null != convertVideoPakcet){
			convertVideoPakcets.remove(id);
			return convertVideoPakcet.stop();
		}

		return false;
	}

	/**
	 * 拉取摄像头视频源
	 * 
	 * @param src rtsp数据源地址
	 * @author JW
	 * @throws Exception
	 */
    private ConvertVideoPakcet rtsp(String src) throws Exception {
		// 采集/抓取器
		grabber = new FFmpegFrameGrabber(src);
		if (src.indexOf("rtsp") >= 0) {
			grabber.setOption("rtsp_transport", "tcp");
		}
		grabber.start();// 开始之后ffmpeg会采集视频信息,之后就可以获取音视频信息
		if (width < 0 || height < 0) {
			width = grabber.getImageWidth();
			height = grabber.getImageHeight();
		}
		// 视频参数
		audiocodecid = grabber.getAudioCodec();
		log.warn("音频编码:{}",audiocodecid);
		codecid = grabber.getVideoCodec();
		framerate = grabber.getVideoFrameRate();// 帧率
		bitrate = grabber.getVideoBitrate();// 比特率
		// 音频参数
		// 想要录制音频,这三个参数必须有:audioChannels > 0 && audioBitrate > 0 && sampleRate > 0
		audioChannels = grabber.getAudioChannels();
		audioBitrate = grabber.getAudioBitrate();
		if (audioBitrate < 1) {
			audioBitrate = 128 * 1000;// 默认音频比特率
		}
		return this;
	}

	/**
	 * rtmp输出推流到nginx媒体流服务器
	 * 
	 * @param out t\ rtmp媒体流服务器地址
	 * @author JW
	 * @throws IOException
	 */
    private ConvertVideoPakcet rtmp(String out) throws IOException {
		// 录制/推流器
		record = new FFmpegFrameRecorder(out, width, height);
		record.setVideoOption("crf", "30");
		record.setGopSize(2);
		record.setFrameRate(framerate);
		record.setVideoBitrate(bitrate);

		record.setAudioChannels(audioChannels);
		record.setAudioBitrate(audioBitrate);
		record.setSampleRate(sampleRate);

		AVFormatContext fc = null;
		
		if (out.indexOf("rtmp") >= 0 || out.indexOf("flv") > 0) {
			// 封装格式flv
			record.setFormat("flv");
			record.setAudioCodecName("aac");
			record.setVideoCodec(codecid);
			fc = grabber.getFormatContext();
		}
		
		record.start(fc);
		
		return this;
	}

	/**
	 * 转封装
	 * 
	 * @author eguid
	 * @throws IOException
	 */
	private void start() throws IOException {

	    //刷新开始的测试数据
		if(null != grabber)
			grabber.flush();

		while (flag) {
			AVPacket pkt = null;
			try {
				// 没有解码的音视频帧
				pkt = grabber.grabPacket();
				if (pkt == null || pkt.size() <= 0 || pkt.data() == null) {
					continue;
				}

				// 不需要编码直接把音视频帧推出去
				record.recordPacket(pkt);
				avcodec.av_packet_unref(pkt);

				try {
					Thread.sleep(0,1000);
				} catch (InterruptedException e) {
					log.error("推流发生等待异常,{}",e);
				}

			} catch (Exception e) {
				log.error("推流发生异常,{}",e);
			} catch (IOException e) {
				log.error("推流发生IO异常,{}",e);
			}
		}
	}

	private Boolean stop() {

		//控制退出循环
		flag = false;

		if(null != record){
			try {
				record.release();
			} catch (FrameRecorder.Exception e) {
				log.error("stop record error ,{}",e);
				return false;
			}
		}

		if(null != grabber){
			try {
				grabber.release();
			} catch (Exception e) {
				log.error("stop grabber error ,{}",e);
				return false;
			}
		}


		return true;
	}

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

		// 运行,设置视频源和推流地址
		new ConvertVideoPakcet().rtsp("rtsp://admin:a1234567@192.168.0.121:554/h264/ch1/main/av_stream")
				.rtmp("rtmp://www.2edge.cn:1985/factory/test").start();
	}
}
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值