1. 程式人生 > >javaCV開發詳解之2:推流器實現,推本地攝像頭視訊到流媒體伺服器以及攝像頭錄製視訊功能實現(基於javaCV-FFMPEG、javaCV-openCV)

javaCV開發詳解之2:推流器實現,推本地攝像頭視訊到流媒體伺服器以及攝像頭錄製視訊功能實現(基於javaCV-FFMPEG、javaCV-openCV)

javaCV系列文章:

補充篇:

  • 歡迎大家積極開心的加入討論群

javacpp-ffmpeg:

前言:

本章將在上一章的基礎上,增加視訊推流到流媒體伺服器和視訊錄製的功能;

功能:實現邊播放邊錄製/推流,停止預覽即停止錄製/推流

提示:

1、本章程式碼從釋出至今測試執行正常,如遇到錯誤請自覺檢查環境配置和jar包問題

2、到目前為止大家遇到的問題100%都是jar包問題,那麼如果遇到各種異常和報錯,請參照第一條,謝謝

一、開發所依賴的包

javacv.jar,javacpp.jar,ffmpeg.jar,ffmpeg-系統平臺.jar,opencv.jar,opencv-系統平臺.jar。

其中ffmpeg-系統平臺.jar,opencv-系統平臺.jar中的系統平臺根據開發環境或者測試部署環境自行更改為對應的jar包,比如windows7 64位系統替換為ffmpeg-x86-x64.jar

為什麼要這樣做:因為ffmpeg-系統平臺.jar中存放的是c/c++本地so/dll庫,而ffmpeg.jar就是使用javacpp封裝的對應本地庫java介面的實現,而javacpp就是基於jni的一個功能性封裝包,方便實現jni,javacv.jar就是對9個視覺庫進行了二次封裝,但是實現的功能有限,所以建議新手先熟悉openCV和ffmpeg這兩個C/C++庫的API後再來看javaCV思路就會很清晰了。

二、程式碼實現

本功能採用按幀錄製/推流,通過關閉播放視窗停止視訊錄製/推流

注:長時間執行該程式碼會導致記憶體溢位的原因是沒有及時釋放IplImage資源(由於javacv是jni方式呼叫C,部分物件需要手動釋放資源,以防止記憶體溢位錯誤)

/**
	 * 按幀錄製本機攝像頭視訊(邊預覽邊錄製,停止預覽即停止錄製)
	 * 
	 * @author eguid
	 * @param outputFile -錄製的檔案路徑,也可以是rtsp或者rtmp等流媒體伺服器釋出地址
	 * @param frameRate - 視訊幀率
	 * @throws Exception
	 * @throws InterruptedException
	 * @throws org.bytedeco.javacv.FrameRecorder.Exception
	 */
	public static void recordCamera(String outputFile, double frameRate)
			throws Exception, InterruptedException, org.bytedeco.javacv.FrameRecorder.Exception {
		Loader.load(opencv_objdetect.class);
		FrameGrabber grabber = FrameGrabber.createDefault(0);//本機攝像頭預設0,這裡使用javacv的抓取器,至於使用的是ffmpeg還是opencv,請自行檢視原始碼
		grabber.start();//開啟抓取器

		OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();//轉換器
		IplImage grabbedImage = converter.convert(grabber.grab());//抓取一幀視訊並將其轉換為影象,至於用這個影象用來做什麼?加水印,人臉識別等等自行新增
		int width = grabbedImage.width();
		int height = grabbedImage.height();
	
		FrameRecorder recorder = FrameRecorder.createDefault(outputFile, width, height);
		recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); // avcodec.AV_CODEC_ID_H264,編碼
		recorder.setFormat("flv");//封裝格式,如果是推送到rtmp就必須是flv封裝格式
		recorder.setFrameRate(frameRate);
		
		recorder.start();//開啟錄製器
		long startTime=0;
		long videoTS=0;
		CanvasFrame frame = new CanvasFrame("camera", CanvasFrame.getDefaultGamma() / grabber.getGamma());
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setAlwaysOnTop(true);
		Frame rotatedFrame=converter.convert(grabbedImage);//不知道為什麼這裡不做轉換就不能推到rtmp
		while (frame.isVisible() && (grabbedImage = converter.convert(grabber.grab())) != null) {
			rotatedFrame = converter.convert(grabbedImage);
			frame.showImage(rotatedFrame);
			if (startTime == 0) {
				startTime = System.currentTimeMillis();
			}
			videoTS = 1000 * (System.currentTimeMillis() - startTime);
			recorder.setTimestamp(videoTS);
			recorder.record(rotatedFrame);
			Thread.sleep(40);
		}
		frame.dispose();
		recorder.stop();
		recorder.release();
		grabber.stop();
	
	}

總的來說,我們已經實現了基本的推流器功能,那麼需要注意的就是轉換那裡,不清楚為什麼不做轉換就不能推送到rtmp流媒體伺服器,如果哪位有更好的方案希望可以聯絡博主,感謝!

3、測試錄製功能和推流功能

public static void main(String[] args) throws Exception, InterruptedException, org.bytedeco.javacv.FrameRecorder.Exception {
		recordCamera("output.mp4",25);
	}
public static void main(String[] args) throws Exception, InterruptedException, org.bytedeco.javacv.FrameRecorder.Exception {
		recordCamera("rtmp://192.168.30.21/live/record1",25);
	}


看到了攝像頭視窗就說明已經開始錄製,點選右上角關閉按鈕即停止錄製視訊,在錄製的時候重新整理專案目錄發現新生成了一個output.mp4檔案,可以正常播放這個視訊檔案

支援eguid原創

到這章我們已經實現了錄製本地攝像頭視訊和推送攝像頭的視訊到伺服器,小夥伴們已經迫不及待的開始線上直播show了 - -!

既然已經實現了線上直播,那麼我們想要儲存或者播放別人的線上直播視訊怎麼辦呢?

下一章將會講解如何錄製流媒體伺服器的視訊到本地檔案,當然是可以線上播放的