MediaExtractor主要用于提取音视频相关信息,分离音视频。
MediaMuxer主要复用和解复用音视频。
MediaExtractor使用一般步骤
1.//设置数据源
setDataSource
2.//分离轨道
getTrackCount,getTrackFormat
3.//选择轨道
selectTrack,unselectTrack
4.//读取数据
readSampleData
5.//下一帧
advance
6.//释放
release
eg:
int trackCount = mediaExtractor.getTrackCount();
for (int i = 0; i < trackCount; i++) {
MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
String mime = trackFormat.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/")) {
mediaExtractor.selectTrack(i);
break;
} else if (mime.startsWith("audio/")) {
mediaExtractor.selectTrack(i);
break;
}
}
MediaMuxer使用一般步骤
1.//添加轨道
addTrack
2.写数据
writeSampleData
3.释放
release
注意点
buffinfo 必须设置相应的有效值,不然会引发错误
//写入数据大小
bufferInfo.size = readSampleDataSize;
//偏移量
bufferInfo.offset = 0;
//是否为关键帧
bufferInfo.flags = mediaExtractor.getSampleFlags();
//PTS 单位为微妙,必须为递增不然会报错
bufferInfo.presentationTimeUs += videoSampleTime;
mediaMuxer.writeSampleData(trackIndex, buffer, bufferInfo);
这里重点关注下
bufferInfo.presentationTimeUs
mediaExtractor.getSampleTime()
因为mediaExtractor的提取顺序应该是dts的顺序不是pts的顺序,如果视频中存在b帧则getSampleTime不可能递增的,所以bufferInfo.presentationTimeUs=mediaExtractor.getSampleTime()可能会报错,前面说了这个值必须递增。如果不存在b帧,pts==dts,使用没问题。
设置PTS的办法
1.算出帧时间距,github上看见的,排除i帧来计算不知道是为什么,不排除感觉也一样的
long videoSampleTime;
// mediaExtractor.readSampleData(buffer, 0);
// //skip first I frame
// if (mediaExtractor.getSampleFlags() == MediaExtractor.SAMPLE_FLAG_SYNC)
// mediaExtractor.advance();
mediaExtractor.readSampleData(buffer, 0);
long firstVideoPTS = mediaExtractor.getSampleTime();
mediaExtractor.advance();
mediaExtractor.readSampleData(buffer, 0);
long SecondVideoPTS = mediaExtractor.getSampleTime();
videoSampleTime = Math.abs(SecondVideoPTS - firstVideoPTS);
2.通过帧率来计算
//每秒多少帧
int frameRate=mediaFormat=getInteger(MediaFormat.KEY_FRAME_RATE)
//得出平均每一帧间隔多少微妙
videoSampleTime=1000*1000/frameRate
最后提供2个简单的运用示例
有耗时,不要ui线程使用,只是演示
/**
* 提取音/视频
*
* @param inPath
* @param outPath
* @param isVideo
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public static void trackExtractor(String inPath, String outPath, boolean isVideo) {
//提取器
MediaExtractor mediaExtractor = new MediaExtractor();
try {
mediaExtractor.setDataSource(inPath);
} catch (IOException e) {
e.printStackTrace();
}
MediaMuxer mediaMuxer = null;
//复用器
try {
mediaMuxer = new MediaMuxer(outPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
} catch (IOException e) {
e.printStackTrace();
}
int trackIndex = 0;
int trackCount = mediaExtractor.getTrackCount();
for (int i = 0; i < trackCount; i++) {
MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
String mime = trackFormat.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/") && isVideo) {
trackIndex = mediaMuxer.addTrack(trackFormat);
mediaExtractor.selectTrack(i);
break;
} else if (mime.startsWith("audio/") && !isVideo) {
trackIndex = mediaMuxer.addTrack(trackFormat);
mediaExtractor.selectTrack(i);
break;
}
}
mediaMuxer.start();
ByteBuffer buffer = ByteBuffer.allocate(1024 * 1000);
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
long videoSampleTime=getSampleTime(mediaExtractor,buffer);
while (true) {
int readSampleDataSize = mediaExtractor.readSampleData(buffer, 0);
if (readSampleDataSize < 0) {
break;
}
bufferInfo.size = readSampleDataSize;
bufferInfo.offset = 0;
bufferInfo.flags = mediaExtractor.getSampleFlags();
bufferInfo.presentationTimeUs += videoSampleTime;
mediaMuxer.writeSampleData(trackIndex, buffer, bufferInfo);
mediaExtractor.advance();
}
mediaExtractor.release();
mediaMuxer.stop();
//内部也会执行stop,所以可以不用执行stop
mediaMuxer.release();
}
private static long getSampleTime(MediaExtractor mediaExtractor, ByteBuffer buffer) {
long videoSampleTime;
// mediaExtractor.readSampleData(buffer, 0);
// //skip first I frame
// if (mediaExtractor.getSampleFlags() == MediaExtractor.SAMPLE_FLAG_SYNC)
// mediaExtractor.advance();
mediaExtractor.readSampleData(buffer, 0);
long firstVideoPTS = mediaExtractor.getSampleTime();
mediaExtractor.advance();
mediaExtractor.readSampleData(buffer, 0);
long SecondVideoPTS = mediaExtractor.getSampleTime();
videoSampleTime = Math.abs(SecondVideoPTS - firstVideoPTS);
Log.d("MediaMuxerUtil", "videoSampleTime is " + videoSampleTime);
return videoSampleTime;
}
/**
* 合成音视频
*
* @param videoPath
* @param audioPath
* @param outPath
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public static void trackMuxer(String videoPath, String audioPath, String outPath) {
MediaExtractor videoExtractor = new MediaExtractor();
try {
videoExtractor.setDataSource(videoPath);
} catch (IOException e) {
e.printStackTrace();
}
MediaFormat videoFormat = null;
int videoTrackIndex = -1;
int videoTrackCount = videoExtractor.getTrackCount();
for (int i = 0; i < videoTrackCount; i++) {
videoFormat = videoExtractor.getTrackFormat(i);
String mime = videoFormat.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/")) {
videoTrackIndex = i;
break;
}
}
MediaExtractor audioExtractor = new MediaExtractor();
try {
audioExtractor.setDataSource(audioPath);
} catch (IOException e) {
e.printStackTrace();
}
MediaFormat audioFormat = null;
int audioTrackIndex = -1;
int audioTrackCount = audioExtractor.getTrackCount();
for (int i = 0; i < audioTrackCount; i++) {
audioFormat = audioExtractor.getTrackFormat(i);
String mime = audioFormat.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("audio/")) {
audioTrackIndex = i;
break;
}
}
videoExtractor.selectTrack(videoTrackIndex);
audioExtractor.selectTrack(audioTrackIndex);
MediaCodec.BufferInfo videoBufferInfo = new MediaCodec.BufferInfo();
MediaCodec.BufferInfo audioBufferInfo = new MediaCodec.BufferInfo();
MediaMuxer mediaMuxer = null;
try {
mediaMuxer = new MediaMuxer(outPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
} catch (IOException e) {
e.printStackTrace();
}
int writeVideoTrackIndex = mediaMuxer.addTrack(videoFormat);
int writeAudioTrackIndex = mediaMuxer.addTrack(audioFormat);
mediaMuxer.start();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1000);
long videoSampleTime=getSampleTime(videoExtractor,byteBuffer);
while (true) {
int readVideoSampleSize = videoExtractor.readSampleData(byteBuffer, 0);
if (readVideoSampleSize < 0) {
break;
}
videoBufferInfo.size = readVideoSampleSize;
videoBufferInfo.presentationTimeUs +=videoSampleTime;
videoBufferInfo.offset = 0;
videoBufferInfo.flags = videoExtractor.getSampleFlags();
mediaMuxer.writeSampleData(writeVideoTrackIndex, byteBuffer, videoBufferInfo);
videoExtractor.advance();
}
long audioSampleTime=getSampleTime(audioExtractor,byteBuffer);
while (true) {
int readAudioSampleSize = audioExtractor.readSampleData(byteBuffer, 0);
if (readAudioSampleSize < 0) {
break;
}
audioBufferInfo.size = readAudioSampleSize;
audioBufferInfo.presentationTimeUs += audioSampleTime;
audioBufferInfo.offset = 0;
audioBufferInfo.flags = audioExtractor.getSampleFlags();
mediaMuxer.writeSampleData(writeAudioTrackIndex, byteBuffer, audioBufferInfo);
audioExtractor.advance();
}
mediaMuxer.stop();
mediaMuxer.release();
videoExtractor.release();
audioExtractor.release();
}