前言
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(): 讀取結束后釋放資源