javaCV开发详解之4:转流器实现(也可作为本地收流器、推流器,新增添加图片及文字水印,视频图像帧保存),实现rtsp/rtmp/本地文件转发到rtmp流媒体服务器(基于javaCV-FFMPEG)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/eguid_1/article/details/52691707

javaCV系列文章:

javacv开发详解之1:调用本机摄像头视频

javaCV开发详解之2:推流器实现,推本地摄像头视频到流媒体服务器以及摄像头录制视频功能实现(基于javaCV-FFMPEG、javaCV-openCV)

javaCV开发详解之3:收流器实现,录制流媒体服务器的rtsp/rtmp视频文件(基于javaCV-FFMPEG)

javaCV开发详解之4:转流器实现(也可作为本地收流器、推流器,新增添加图片及文字水印,视频图像帧保存),实现rtsp/rtmp/本地文件转发到rtmp流媒体服务器(基于javaCV-FFMPEG)

javaCV开发详解之5:录制音频(录制麦克风)到本地文件/流媒体服务器(基于javax.sound、javaCV-FFMPEG)

javaCV开发详解之6:本地音频(话筒设备)和视频(摄像头)抓取、混合并推送(录制)到服务器(本地)

javaCV开发详解之7:让音频转换更加简单,实现通用音频编码格式转换、重采样等音频参数的转换功能(以pcm16le编码的wav转mp3为例)

javaCV开发详解之8:转封装在rtsp转rtmp流中的应用(无须转码,更低的资源消耗,更好的性能,更低延迟)

补充篇:

音视频编解码问题:javaCV如何快速进行音频预处理和解复用编解码(基于javaCV-FFMPEG)

音视频编解码问题:16/24/32位位音频byte[]转换为小端序short[],int[],以byte[]转short[]为例

实现给图片增加图片水印或者文字水印(也支持视频图像帧添加水印)

javacpp-ffmpeg:

javacpp-FFmpeg拉流解码成YUVJ420P,并保存为jpg图片

前言:

上一章中实现了本地推流器和本地摄像头录制功能:http://blog.csdn.net/eguid_1/article/details/52678775

本章基于javaCV实现转流器和收流器功能,测试采用监控rtsp地址转发至rtmp服务器地址

更好的转流实现参照这章:javaCV开发详解之8:转封装在rtsp转rtmp流中的应用(无须转码,更低的资源消耗,更好的性能,更低延迟)

新增openCV保存图片功能。

补充:

作为转流器可以轻松实现rtsp/rtmp/本地文件/本地摄像头推送到rtmp流媒体服务器;

作为收流器可以用来把流媒体服务器视频流录制到本地文件。

关于默认接收/推送rtsp流丢帧问题,由于ffmpeg默认采用udp方式,所以可以通过更改为tcp的方式来实现丢帧补偿,解决方式如下:

1、FFmpeg命令方式:增加一个配置命令 -rtsp_transport tcp

2、javacv方式:FFmpegFrameGrabber.java中533行 AVDictionary options= new AVDictionary(null);后面增加一个配置av_dict_set(options, "rtsp_transport", "tcp", 0); 即可

3、ffmpeg原生方式:同上

一、开发所依赖的包(具体依赖包请查看javacv开发详解之1

本章使用windows环境开发,基于javaCV的基础支撑包以及ffmpeg-3.1.2-1.2.jar、ffmpeg-3.1.2-1.2-windows-x86.jar、ffmpeg-3.1.2-1.2-windows-x86_64.jar;

 

补充:

如果想要给视频添加水印,需要从视频中取出图像帧,给图像帧添加文字、图片水印即可

在此之前我们需要取到BufferedImage,通过这个我们就可以用java的方式添加水印

如何用java添加水印:http://blog.csdn.net/eguid_1/article/details/52973508

如何从grabber中获取BufferedImage:

 

//获取BufferedImage可以给图像帧添加水印
		Java2DFrameConverter javaconverter=new Java2DFrameConverter();
		BufferedImage buffImg=javaconverter.convert(grabber.grab());

获取到了BufferedImage我们就可以给视频帧添加文字或者图片水印了

二、代码实现

 

本功能实现按帧取流和转发服务

 

 

 

/**
	 * 转流器
	 * @param inputFile
	 * @param outputFile
	 * @throws Exception
	 * @throws org.bytedeco.javacv.FrameRecorder.Exception
	 * @throws InterruptedException
	 */
	public static void recordPush(String inputFile,String outputFile,int v_rs) throws Exception, org.bytedeco.javacv.FrameRecorder.Exception, InterruptedException{
		Loader.load(opencv_objdetect.class);
		long startTime=0;
		FrameGrabber grabber =FFmpegFrameGrabber.createDefault(inputFile);
		try {
			grabber.start();
		} catch (Exception e) {
			try {
				grabber.restart();
			} catch (Exception e1) {
				throw e;
			}
		}
		
		OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
		Frame grabframe =grabber.grab();
		IplImage grabbedImage =null;
		if(grabframe!=null){
			System.out.println("取到第一帧");
			grabbedImage = converter.convert(grabframe);
		}else{
			System.out.println("没有取到第一帧");
		}
		//如果想要保存图片,可以使用 opencv_imgcodecs.cvSaveImage("hello.jpg", grabbedImage);来保存图片
		FrameRecorder recorder;
		try {
			recorder = FrameRecorder.createDefault(outputFile, 1280, 720);
		} catch (org.bytedeco.javacv.FrameRecorder.Exception e) {
			throw e;
		}
		recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // avcodec.AV_CODEC_ID_H264
		recorder.setFormat("flv");
		recorder.setFrameRate(v_rs);
		recorder.setGopSize(v_rs);
		System.out.println("准备开始推流...");
		try {
			recorder.start();
		} catch (org.bytedeco.javacv.FrameRecorder.Exception e) {
			try {
				System.out.println("录制器启动失败,正在重新启动...");
				if(recorder!=null)
				{
					System.out.println("尝试关闭录制器");
					recorder.stop();
					System.out.println("尝试重新开启录制器");
					recorder.start();
				}
				
			} catch (org.bytedeco.javacv.FrameRecorder.Exception e1) {
				throw e;
			}
		}
		System.out.println("开始推流");
		CanvasFrame frame = new CanvasFrame("camera", CanvasFrame.getDefaultGamma() / grabber.getGamma());
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setAlwaysOnTop(true);
		while (frame.isVisible() && (grabframe=grabber.grab()) != null) {
			System.out.println("推流...");
			frame.showImage(grabframe);
			grabbedImage = converter.convert(grabframe);
			Frame rotatedFrame = converter.convert(grabbedImage);
			
			if (startTime == 0) {
				startTime = System.currentTimeMillis();
			}
			recorder.setTimestamp(1000 * (System.currentTimeMillis() - startTime));//时间戳
			if(rotatedFrame!=null){
			recorder.record(rotatedFrame);
			}
			
			Thread.sleep(40);
		}
		frame.dispose();
		recorder.stop();
		recorder.release();
		grabber.stop();
		System.exit(2);
	}

 

三、测试转流服务

public static void main(String[] args)
			throws FrameRecorder.Exception, FrameGrabber.Exception, InterruptedException {

		 String inputFile = "rtsp://admin:admin@192.168.2.236:37779/cam/realmonitor?channel=1&subtype=0";

		String outputFile="rtmp://192.168.30.21/live/pushFlow";

		recordPush(inputFile, outputFile,25);

支持eguid原创

 

 

 

展开阅读全文

没有更多推荐了,返回首页