MediaExtractor
视音频分离器,将一些格式的视频分离出视频轨道和音频轨道。
主要流程,也是主要的 API:
- setDataSource(String path):设置数据源
- getTrackCount():获取通道数
- getTrackFormat(int index):获取通道格式
- readSampleData(ByteBuffer byteBuf, int offset):读取指定通道中的数据
- getSampleTime():获取当前时间戳
- advance():下一帧
- release():释放资源
MediaMuxer
视音频合成器,将视频和音频合成相应的格式
- MediaMuxer(String path, int format):初始化输出文件名称和输出文件的格式:mpeg4
- addTrack(MediaFormat format):添加轨道,返回 track Index,会在 writeSampleData 中使用
- start():开始合成文件
- writeSampleData(int, ByteBuffer, MediaCodec.BufferInfo):写数据
- stop():停止合成文件
- release():释放资源
大体流程:
以下是分离 mp4 音频和视频的源码及注释:
private String seperateMedia(String fileName, boolean isAudio) {
String type = isAudio ? "audio/" : "video/";
MediaExtractor mMediaExtractor = new MediaExtractor();;
MediaMuxer mMediaMuxer = null;
try {
mMediaMuxer = new MediaMuxer(getSDPath() + "/" + fileName, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
// 获取assert中的资源文件
AssetFileDescriptor fileDescriptor = getAssetFileSource();
// 设置资源文件
mMediaExtractor.setDataSource(fileDescriptor.getFileDescriptor(), fileDescriptor.getStartOffset(), fileDescriptor.getLength());
int mMediaIndex = 0;
for (int i = 0; i < mMediaExtractor.getTrackCount(); i++) {
//获取码流的详细格式/配置信息
MediaFormat format = mMediaExtractor.getTrackFormat(i);
String mine = format.getString(MediaFormat.KEY_MIME);
// 查找音频:"audio/" 或者视频:"video/"的轨道
if (mine.startsWith(type)) {
mMediaIndex = i;
break;
}
}
// 选择感兴趣的轨道
mMediaExtractor.selectTrack(mMediaIndex);
// 获取通道格式,可以自己新建,但是有坑
MediaFormat mediaFormat = mMediaExtractor.getTrackFormat(mMediaIndex);
int muxerTrackIndex = mMediaMuxer.addTrack(mediaFormat);
// 当采集视频的使用,需要获取帧率,音频轨道没有这个参数
int framerate = isAudio ? 0 : mediaFormat.getInteger(MediaFormat.KEY_FRAME_RATE);
mMediaMuxer.start();
ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024);
int readSize = 0;
// writeSampleData需要BufferInfo参数
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
while((readSize = mMediaExtractor.readSampleData(byteBuffer, 0)) > 0) {
bufferInfo.size = readSize;
bufferInfo.flags = mMediaExtractor.getSampleFlags(); //设置为关键帧等
bufferInfo.offset = 0;
if (!isAudio) { // 时间戳,音频和视频的处理方式不一样
bufferInfo.presentationTimeUs += 1000 * 1000 / framerate;
} else {
bufferInfo.presentationTimeUs = mMediaExtractor.getSampleTime();
}
mMediaMuxer.writeSampleData(muxerTrackIndex, byteBuffer, bufferInfo);
Log.d("getSampleTime", "seperateMedia: " + mMediaExtractor.getSampleTime() );
mMediaExtractor.advance();