MediaExtractor与MediaMuxer工具可以完美的将视频中的音视频分开来,可以对视频进行再配音合成达到自己的需求:
1.准备工作:声明基础变量
private final static String ROOT_PATH = Environment.getExternalStorageDirectory()
.getAbsolutePath()+"/Media";
private final static String MEDIA_DIVIDE_PATH = ROOT_PATH+"/divide";
private final static String MEDIA_DUBBING_PATH = ROOT_PATH+"/dubbing";
private String currentTaskPath = null;
public final static String AUDIO_MIME = "audio";
public final static String VIDEO_MIME = "video";
private String videoOutputPath;
public MediaDivider(){
initOutputPath();
}
private void initOutputPath(){
File file = new File(ROOT_PATH);
if (!file.exists()) {
file.mkdirs();
}
File divide = new File(MEDIA_DIVIDE_PATH);
if (!divide.exists()) {
divide.exists();
}
currentTaskPath = createCurrentTaskPath();
File currentTask = new File(currentTaskPath);
if (!currentTask.exists()) {
currentTask.mkdirs();
}
File dubbingPath = new File(MEDIA_DUBBING_PATH);
if (!dubbingPath.exists()) {
dubbingPath.mkdirs();
}
}
private String createCurrentTaskPath(){
return MEDIA_DIVIDE_PATH+"/"+System.currentTimeMillis();
}
2.开始分离音视频:
public void divideMedia(String sourceMediaPath,String divideMime){
MediaExtractor mediaExtractor = new MediaExtractor();
try {
mediaExtractor.setDataSource(sourceMediaPath);
int trackCount = mediaExtractor.getTrackCount();
for (int i=0;i<trackCount;i++) {
MediaFormat mediaFormat = mediaExtractor.getTrackFormat(i);
String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
if (!mime.startsWith(divideMime)) {
continue;
}
int maxInputSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
Log.d(TAG,"maxInputSize:"+maxInputSize);
ByteBuffer videoByteBuffer = ByteBuffer.allocate(maxInputSize);
if (divideMime.equals(AUDIO_MIME)) {
Log.d(TAG,"divide audio media to file");
String audioName = currentTaskPath+"/"
+sourceMediaPath.substring(sourceMediaPath.lastIndexOf('/')+1,sourceMediaPath.lastIndexOf('.'))
+"_audio_out.mp4";
Log.d(TAG,"audioName:"+audioName);
MediaMuxer mediaMuxer = new MediaMuxer(audioName,MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
int audioTrack = mediaMuxer.addTrack(mediaFormat);
mediaMuxer.start();
divideToOutputAudio(mediaExtractor,mediaMuxer,videoByteBuffer,mediaFormat,audioTrack,i);
finish(mediaExtractor,mediaMuxer);
break;
} else if (divideMime.equals(VIDEO_MIME)) {
Log.d(TAG,"divide video media to file");
String videoName = currentTaskPath+"/"
+sourceMediaPath.substring(sourceMediaPath.lastIndexOf('/')+1,sourceMediaPath.lastIndexOf('.'))
+"_video_out.mp4";
Log.d(TAG,"videoName:"+videoName);
MediaMuxer mediaMuxer = new MediaMuxer(videoName,MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
int videoTrack = mediaMuxer.addTrack(mediaFormat);
mediaMuxer.start();
divideToOutputVideo(mediaExtractor,mediaMuxer,videoByteBuffer,mediaFormat,videoTrack,i);
finish(mediaExtractor,mediaMuxer);
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
该方法接受视频路径与所要分离出的媒体文件格式:audio或者video,根据媒体格式进行操作。
3.分离视频:
private void divideToOutputVideo(MediaExtractor mediaExtractor,MediaMuxer mediaMuxer,ByteBuffer byteBuffer,MediaFormat format,
int videoTrack,int videoTrackIndex) {
long videoDuration = format.getLong(MediaFormat.KEY_DURATION);
mediaExtractor.selectTrack(videoTrackIndex);
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
bufferInfo.presentationTimeUs = 0;
long videoFrameTimes;
mediaExtractor.readSampleData(byteBuffer,0);
if (mediaExtractor.getSampleFlags()!=MediaExtractor.SAMPLE_FLAG_SYNC) {
mediaExtractor.advance();
}
mediaExtractor.readSampleData(byteBuffer,0);
mediaExtractor.advance();
long firstFrame = mediaExtractor.getSampleTime();
mediaExtractor.advance();
mediaExtractor.readSampleData(byteBuffer,0);
long secondFrame = mediaExtractor.getSampleTime();
videoFrameTimes = Math.abs(secondFrame-firstFrame);
mediaExtractor.seekTo(0,MediaExtractor.SEEK_TO_CLOSEST_SYNC);
int sampleSize;
while ((sampleSize=mediaExtractor.readSampleData(byteBuffer,0))!=-1){
long presentTime = bufferInfo.presentationTimeUs;
if (presentTime>=videoDuration) {
mediaExtractor.unselectTrack(videoTrackIndex);
break;
}
mediaExtractor.advance();
bufferInfo.offset=0;
bufferInfo.flags=mediaExtractor.getSampleFlags();
bufferInfo.size=sampleSize;
mediaMuxer.writeSampleData(videoTrack,byteBuffer,bufferInfo);
bufferInfo.presentationTimeUs +=videoFrameTimes;
}
mediaExtractor.unselectTrack(videoTrackIndex);
}
4.分离出音频:
private void divideToOutputAudio(MediaExtractor mediaExtractor,MediaMuxer mediaMuxer,ByteBuffer byteBuffer,MediaFormat format,
int audioTrack,int audioTrackIndex){
int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
Log.d(TAG,"rate:"+sampleRate+",c:"+channelCount);
long audioDuration = format.getLong(MediaFormat.KEY_DURATION);
mediaExtractor.selectTrack(audioTrackIndex);//参数为多媒体文件MediaExtractor获取到的track count的索引,选择音频轨道
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
bufferInfo.presentationTimeUs = 0;
long audioSampleSize;
mediaExtractor.readSampleData(byteBuffer,0);
if (mediaExtractor.getSampleTime()==0) {
mediaExtractor.advance();
}
mediaExtractor.readSampleData(byteBuffer,0);
long firstRateSample = mediaExtractor.getSampleTime();
mediaExtractor.advance();
mediaExtractor.readSampleData(byteBuffer,0);
long secondRateSample = mediaExtractor.getSampleTime();
audioSampleSize = Math.abs(secondRateSample-firstRateSample);
mediaExtractor.seekTo(0,MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
int sampleSize;
while ((sampleSize=mediaExtractor.readSampleData(byteBuffer,0))!=-1) {
int trackIndex = mediaExtractor.getSampleTrackIndex();
long presentationTimeUs = bufferInfo.presentationTimeUs;
Log.d(TAG,"trackIndex:"+trackIndex+",presentationTimeUs:"+presentationTimeUs);
if (presentationTimeUs>=audioDuration){
mediaExtractor.unselectTrack(audioTrackIndex);
break;
}
mediaExtractor.advance();
bufferInfo.offset=0;
bufferInfo.size=sampleSize;
mediaMuxer.writeSampleData(audioTrack,byteBuffer,bufferInfo);//audioTrack为通过mediaMuxer.add()获取到的
bufferInfo.presentationTimeUs += audioSampleSize;
}
mediaExtractor.unselectTrack(audioTrackIndex);
}
5.释放资源:
private void finish(MediaExtractor mediaExtractor,MediaMuxer mediaMuxer){
mediaMuxer.stop();
mediaMuxer.release();
mediaMuxer = null;
mediaExtractor.release();
mediaExtractor = null;
}