前言:
上一章簡單的介紹了javacv並且演示了如何獲取本機攝像頭:http://blog.csdn.net/eguid_1/article/details/51659578
本章將在上一章的基礎上,增加視頻推流到流媒體服務器和視頻錄制的功能;
功能:實現邊播放邊錄制/推流,停止預覽即停止錄制/推流
提示:
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,通過這種方式創建的資源無法通過虛擬機的GC來清理內存,需要手動進行釋放資源,以防止內存溢出錯誤)
/**
* 按幀錄制本機攝像頭視頻(邊預覽邊錄制,停止預覽即停止錄制)
*
* @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);
}