前言
MediaExtractor字面意思是多媒體提取器,它在Android的音視訊開發裡主要負責提取視訊或者音頻中的資訊和資料流(例如将視訊檔案,剝離出音頻與視訊).本章部落格将講解一些入門簡單的東西.如何分别音頻和視訊軌道和擷取視訊裡的一些資訊.我将在其他章節裡講解其他MediaExtractor使用方法.
擷取軌道
在一個多媒體視訊裡,可以包含多個資料流(一般是視訊與音頻各一個,但是音頻可以多個).我們需要先擷取需要的資料軌道編号,才能後續的各種操作.是以使用MediaExtractor的第一步就是擷取軌道.如下代碼展示了擷取軌道的方法.
列舉所有軌道編碼格式的Demo方法
private void trackDemo(){
mFile = new File(getExternalCacheDir(),"demo.mp4");
if (!mFile.exists()){
Log.e(TAG, "mp4檔案不存在");
return;
}
MediaExtractor extractor = new MediaExtractor();//執行個體一個MediaExtractor
try {
extractor.setDataSource(mFile.getAbsolutePath());//設定添加MP4檔案路徑
} catch (IOException e) {
e.printStackTrace();
}
int count = extractor.getTrackCount();//擷取軌道數量
Log.e(TAG, "軌道數量 = "+count);
for (int i = 0; i < count; i++){
MediaFormat mediaFormat = extractor.getTrackFormat(0);
Log.e(TAG, i+"編号通道格式 = "+mediaFormat.getString(MediaFormat.KEY_MIME));
}
}
上面的代碼已經注釋的很清楚了.注意! 實際項目裡建議将這些操作放到線程中.
結果:
2019-08-19 17:08:21.197 18775-18775/demo.yt.com.demo E/測試Demo: 軌道數量 = 2
2019-08-19 17:08:21.198 18775-18775/demo.yt.com.demo E/測試Demo: 0編号通道格式 = video/avc
2019-08-19 17:08:21.198 18775-18775/demo.yt.com.demo E/測試Demo: 1編号通道格式 = audio/mp4a-latm
從結果可以看到,這個demo.mp4視訊檔案有2個軌道數量,一個是視訊流的軌道,一個是音頻流的軌道.
通過編碼格式字元串對比擷取指定軌道的方法
private Integer getTrackIndex(String targetTrack) {
MediaExtractor extractor = new MediaExtractor();//執行個體一個MediaExtractor
try {
extractor.setDataSource(mFile.getAbsolutePath());//設定添加MP4檔案路徑
} catch (IOException e) {
e.printStackTrace();
}
Integer trackIndex = null;
int count = extractor.getTrackCount();//擷取軌道數量
for (int i = 0; i < count; i++) {
MediaFormat mediaFormat = extractor.getTrackFormat(i);
String currentTrack = mediaFormat.getString(MediaFormat.KEY_MIME);
if (currentTrack.startsWith(targetTrack)) {
trackIndex = i;
break;
}
}
return trackIndex;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_media_extractor);
mFile = new File(getExternalCacheDir(), "demo.mp4");
int index = getTrackIndex("video/");
Log.e(TAG, "onCreate: index = " + index);
}
提取視訊資料資訊
從MediaFormat裡擷取資料資訊
在上面的擷取軌道的代碼裡我們,可以看到使用MediaFormat可以擷取目前軌道的編碼格式.除了擷取編碼格式我們還能擷取到很多其他資訊.這裡我們将會一一列出,但是視訊裡的一些資料是肯定可以擷取到的,而一些其他資料是需要看視訊是否攜帶這些這些資料,如果未攜帶操作擷取這些資料會抛出空指針錯誤.
基本可以擷取到的資訊
1.擷取MIME資訊,上面也有已經示範過了
MediaFormat mediaFormat = extractor.getTrackFormat(0);//擷取多媒體格式,因為是demo已經确定自己的視訊檔案沒問題,是以直接擷取0位軌道
String mimeFormat = mediaFormat.getString(MediaFormat.KEY_MIME);//擷取MIME格式内容
Log.e(TAG, "mediaExtractor: 擷取MIME格式内容="+mimeFormat);
2.擷取語言格式(大多數情況是擷取到空的字元串,但是至少不會報null)
MediaFormat mediaFormat = extractor.getTrackFormat(0);
String language = mediaFormat.getString(MediaFormat.KEY_LANGUAGE);//擷取語言格式内容
Log.e(TAG, "mediaExtractor: 擷取語言格式内容="+language);
3.視訊的高度與寬度
MediaFormat mediaFormat = extractor.getTrackFormat(0);
int width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);//擷取高度
int height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);//擷取高度
4.播放總時長
long durationTime = mediaFormat.getLong(MediaFormat.KEY_DURATION);//總時間
5.擷取MediaFormat描述的資料緩沖區的最大位元組數的鍵
int maxByteCount = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);//擷取視訊緩存輸出的最大大小
不确定可以擷取到的資訊
1.擷取采樣率
int sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);//擷取采樣率
2.擷取比特率
int bitRate = mediaFormat.getInteger(MediaFormat.KEY_BIT_RATE);//擷取比特
3.擷取聲道數量
int channelCount = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);//擷取聲道數量
4.擷取最大高度與最大寬度
int maxWidth = mediaFormat.getInteger(MediaFormat.KEY_MAX_WIDTH);//最大寬度
int maxHeight = mediaFormat.getInteger(MediaFormat.KEY_MAX_HEIGHT);//最大高度
5.擷取顔色格式
int colorFormat = mediaFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT);//顔色格式
6.擷取幀率
int frameRate = mediaFormat.getInteger(MediaFormat.KEY_FRAME_RATE);//幀率
7.擷取圖塊的高度與寬度
int tileWidth = mediaFormat.getInteger(MediaFormat.KEY_TILE_WIDTH);//圖塊分辨率
int tileHeight = mediaFormat.getInteger(MediaFormat.KEY_TILE_HEIGHT);//圖塊分辨率
8.擷取網格行
int gridRows = mediaFormat.getInteger(MediaFormat.KEY_GRID_ROWS);//網格行
9.擷取網格列
int gridColumns = mediaFormat.getInteger(MediaFormat.KEY_GRID_COLUMNS);//網格列
10.PCM-編碼 模拟信号編碼
int pcmEncoding = mediaFormat.getInteger(MediaFormat.KEY_PCM_ENCODING);//PCM-編碼 模拟信号編碼
11.捕獲率
float captureRate = mediaFormat.getFloat(MediaFormat.KEY_CAPTURE_RATE);//捕獲率
12.是否是AAS
int isAdts = mediaFormat.getInteger(MediaFormat.KEY_IS_ADTS);
API清單
- setDataSource(String path):即可以設定本地檔案又可以設定網絡檔案
- getTrackCount():得到源檔案通道數
- getTrackFormat(int index):擷取指定(index)的通道格式
- getSampleTime():傳回目前的時間戳
- readSampleData(ByteBuffer byteBuf, int offset):把指定通道中的資料按偏移量讀取到ByteBuffer中;
- advance():讀取下一幀資料
- release(): 讀取結束後釋放資源
end