在音视频处理的时候,省不了的就是解封装的操作,下面介绍一下,如何使用 Android 系统 api MediaExtractor,实现音视频的解封装。
初始化
一般来说,这里直接传文件路径进去就可以了,但是有时候我们拿到的不是文件路径,那么可以转成 fd 后在传给 MediaExtractor。
public AVHWReader(String file, Context context) {
mediaExtractor = new MediaExtractor();
FileDescriptor fd = null;
try {
mediaExtractor.setDataSource(file);
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
}
获取轨道
通过 MIME 我们能获取音频、视频的轨道信息。
public int getVideoTrackIndex() {
return getTrackIndex("video/");
}
public int getAudioTrackIndex() {
return getTrackIndex("audio/");
}
public MediaFormat getMediaFormat(int trackIndex) {
return mediaExtractor.getTrackFormat(trackIndex);
}
public MediaFormat getVideoMediaFormat() {
int trackIndex = getVideoTrackIndex();
return mediaExtractor.getTrackFormat(trackIndex);
}
读数据
这里的 ByteBuffer 要足够大,不然会产生异常。如果要同时读音视频数据,建议使用两个 Extractor。
public AVPacket readPacket(int trackIndex) {
mediaExtractor.selectTrack(trackIndex);
//if size too small, will produce illegal argument error
ByteBuffer inputBuffer = ByteBuffer.allocate(1024*1024);
int sampleSize = -1;
try {
sampleSize = mediaExtractor.readSampleData(inputBuffer,0);
}catch (Exception e) {
Log.e(TAG, e.getMessage());
}
if (sampleSize == -1) {
return null;
}
AVPacket packet = new AVPacket();
packet.buffer = inputBuffer;
packet.dts = mediaExtractor.getSampleTime();
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
bufferInfo.offset = 0;
bufferInfo.size = inputBuffer.limit();
bufferInfo.flags = mediaExtractor.getSampleFlags();
bufferInfo.presentationTimeUs = mediaExtractor.getSampleTime();
packet.bufferInfo = bufferInfo;
mediaExtractor.advance();
return packet;
}
关闭
释放资源
public void stopReading() {
mediaExtractor.release();
}