描述
視頻文件中包含視頻和音頻數(shù)據(jù)眼刃,那如何通過Java將處理音視頻文件师郑,這里案例使用OpenCV的視覺框架欣鳖,OpenCV對FFMPEG(音視頻)框架做了封裝采呐。
OpenCV的jar包支持跨平臺:window系統(tǒng)、Linux系統(tǒng)(x86-x64 arm)吼畏、macos
核心類
FFmpegFrameGrabber 它可以打開本地視頻或拉取RTMP流媒體服務器督赤。內(nèi)部實現(xiàn)FFMPEG中的 解復用->解碼->像素轉(zhuǎn)換->重采樣等操作
FFmpegFrameRecorder 將視頻中每一幀數(shù)據(jù)存儲音頻或視頻數(shù)據(jù)存儲到本地。內(nèi)部實現(xiàn)FFMPEG中的 復用->編碼->封裝包->數(shù)據(jù)到本地
FFmpegFrameGrabber 類方法
方法名稱 | 方法描述 |
---|---|
FFmpegFrameGrabber(String filename) | 構(gòu)造函數(shù)泻蚊,實例化傳入文件路徑躲舌,或流媒體地址 |
setFrameRate | 設(shè)置視頻幀率 |
setGopSize | 設(shè)置視頻gop,與幀率相同,相當于間隔1秒chan's一個關(guān)鍵幀 |
setVideoCodec | 設(shè)置壓縮方式 性雄,如AV_CODEC_ID_H264没卸,AV_CODEC_ID_MJPEG等 |
setPixelFormat | 設(shè)置封裝格式 |
setVideoOption | 設(shè)置ffmpeg參數(shù) |
start | 開啟視頻解碼操作 |
setOption | 設(shè)置ffmpeg參數(shù),如:rtsp_transport |
grab() | 獲取一幀解碼數(shù)據(jù) |
getImageWidth() | 視頻寬 |
getImageHeight() | 視頻高 |
getAudioChannels() | 音頻聲道數(shù)量,單聲道秒旋,雙聲道 |
grabPacket() | FFMPEG包數(shù)據(jù) |
FFmpegFrameRecorder 類方法
方法名稱 | 方法描述 |
---|---|
FFmpegFrameRecorder(String filename, int imageWidth, int imageHeight) | 設(shè)置視頻文件存放路徑 |
FFmpegFrameRecorder(String filename, int audioChannels) | 設(shè)置音頻文件存放路徑 |
FFmpegFrameRecorder(String filename, int imageWidth, int imageHeight, int audioChannels) | 設(shè)置音視頻存放路徑 |
setVideoOption | 設(shè)置視頻參數(shù)约计,參考ffmpeg |
setFrameRate | 設(shè)置幀率 |
setGopSize | 設(shè)置gop,與幀率相同,相當于間隔1秒chan's一個關(guān)鍵幀 |
setVideoCodec | 設(shè)置壓縮方式 迁筛,如AV_CODEC_ID_H264煤蚌,AV_CODEC_ID_MJPEG等 |
setPixelFormat | 設(shè)置封裝格式 |
setAudioCodec | 設(shè)置音頻編碼格式 |
start | 開始錄制 |
recordPacket | 寫入AVPacket包數(shù)據(jù) |
grab | 寫入Frame解壓數(shù)據(jù) |
引入Maven依賴
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv-platform</artifactId>
<version>4.5.3-1.5.6</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg-platform</artifactId>
<version>4.4-1.5.6</version>
</dependency>
音視頻分離存儲
package com.xl.ffmpeg;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.FFmpegLogCallback;
import org.bytedeco.javacv.Frame;
import static org.bytedeco.ffmpeg.global.avutil.*;
public class Test4 {
public static void main(String[] args) throws Exception {
//開啟日志
FFmpegLogCallback.set();
String inputUrl="2.mp4";
//抽取視頻和音頻存儲路徑
String outputVideoUrl="d:\\1.mp4";
String outputaduioUrl="d:\\2.aac";
//1.拉取視頻
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputUrl);
grabber.start();
//2.錄制視頻
FFmpegFrameRecorder videoRecorder=new FFmpegFrameRecorder(outputVideoUrl,grabber.getImageWidth(),grabber.getImageHeight());
videoRecorder.setFrameRate(25);// 設(shè)置幀率
videoRecorder.setGopSize(25);// 設(shè)置gop,與幀率相同,相當于間隔1秒chan's一個關(guān)鍵幀
videoRecorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); //壓縮方式264
videoRecorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); //視頻源數(shù)據(jù)yuv
videoRecorder.setVideoOption("threads", "8"); //解碼線程數(shù)
videoRecorder.start();
//3.錄制音頻
FFmpegFrameRecorder audioRecorder=new FFmpegFrameRecorder(outputaduioUrl,grabber.getAudioChannels());
audioRecorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC); //設(shè)置音頻壓縮方式
audioRecorder.start();
//讀取每一種數(shù)據(jù)细卧,一幀數(shù)據(jù)可能是音頻或視頻
Frame avFrame=null;
while((avFrame = grabber.grab())!=null){
if(avFrame.streamIndex==AVMEDIA_TYPE_VIDEO){ //視頻幀
videoRecorder.record(avFrame); //錄制視頻
}else if(avFrame.streamIndex==AVMEDIA_TYPE_AUDIO){ //音頻幀
audioRecorder.record(avFrame); //錄制音頻
}
}
//關(guān)閉相關(guān)對象
grabber.close();
videoRecorder.close();
audioRecorder.close();
}
}
RTMP拉流存儲
package com.xl.ffmpeg;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.FFmpegLogCallback;
import org.bytedeco.javacv.Frame;
import static org.bytedeco.ffmpeg.global.avutil.*;
public class Test4 {
public static void main(String[] args) throws Exception {
//開啟日志
FFmpegLogCallback.set();
String inputUrl="rtmp://58.200.131.2:1935/livetv/hunanhd";
//抽取視頻和音頻存儲路徑
String outputVideoUrl="d:\\1.flv";
//1.拉取視頻
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputUrl);
grabber.setOption("threads", "1");
// 設(shè)置緩存大小尉桩,提高畫質(zhì)、減少卡頓花屏
grabber.setOption("buffer_size", "1024000");
// 讀寫超時贪庙,適用于所有協(xié)議的通用讀寫超時
grabber.setOption("rw_timeout", "15000000");
// 探測視頻流信息蜘犁,為空默認5000000微秒
grabber.setOption("probesize","15000000");
// 解析視頻流信息,為空默認5000000微秒
grabber.setOption("analyzeduration", "15000000");
// rtmp拉流緩沖區(qū)止邮,默認3000毫秒
grabber.setOption("rtmp_buffer", "1000");
grabber.start();
//2.錄制視頻/音頻
FFmpegFrameRecorder recorder=new FFmpegFrameRecorder(outputVideoUrl,grabber.getImageWidth(),grabber.getImageHeight());
recorder.setFrameRate(25);// 設(shè)置幀率
recorder.setGopSize(25);// 設(shè)置gop,與幀率相同这橙,相當于間隔1秒chan's一個關(guān)鍵幀
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); //壓縮方式264
recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); //視頻源數(shù)據(jù)yuv
recorder.setVideoOption("threads", "8"); //解碼線程數(shù)
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC); //設(shè)置音頻壓縮方式
recorder.setFormat("flv");
recorder.start();
//讀取每一種數(shù)據(jù),一幀數(shù)據(jù)可能是音頻或視頻
Frame avFrame=null;
while((avFrame = grabber.grab())!=null){
recorder.record(avFrame); //錄制
}
//關(guān)閉相關(guān)對象
grabber.close();
recorder.close();
}
}