使用MediaMuxer裁剪视频
剪辑的过程大概是,先把封装格式的视频文件通过MediaExtractor进行解封装操作,分出不同的tracks,然后针对不同的tracks进行seekTo到我们需要开始裁剪的地方,然后通过MediaMuxer进行合并成封装格式
简要步骤如下
1.解封装,获取不同tracks上的format
mediaExtractor.setDataSource(srcPath);
for(int i=0;i<mediaExtractor.getTrackCount();i++){
if(mediaExtractor.getTrackFormat(i).getString(MediaFormat.KEY_MIME).startsWith("video/")){
sourceVideoTrack = i;
}else if(mediaExtractor.getTrackFormat(i).getString(MediaFormat.KEY_MIME).startsWith("audio/")){
sourceAudioTrack = i;
}
}
videoFormat = mediaExtractor.getTrackFormat(sourceVideoTrack);
audioFormat = mediaExtractor.getTrackFormat(sourceAudioTrack);
2.配置MediaMuxer
(1)初始化该MediaMuxer
//dstPath_cut 为保存的目的地址
mediaMuxer = new MediaMuxer(dstPath_cut, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
(2)addTrack到MediaMuxer
//视频部分
//把视频部分对应的format取出,并将其addTrack到mediaMuxer中
videoTrackIndex = mediaMuxer.addTrack(videoFormat); //addTrack后返回的Index是要保存的,要在后面writeSampleData中使用
//注意视频本身的rotation
int rotation = videoFormat.getInteger(MediaFormat.KEY_ROTATION);
mediaMuxer.setOrientationHint(rotation);
-----------------------------------------------------------------
//音频部分
audioTrackIndex = mediaMuxer.addTrack(audioFormat);
(3)启动MediaMuxer
mediaMuxer.start();
3.向MediaMuxer中写入数据
准备一个ByteBuffer来接收暂存数据
ByteBuffer inputBuffer = ByteBuffer.allocate(BufferSize); //这个BufferSize的大小没有明确的限定,适合即可
//可以通过mediaFormat.getInteger("KEY_MAX_INPUT_SIZE")来获取
写数据
(1)视频部分
//视频部分
mediaExtractor.selectTrack(sourceVideoTrack);
MediaCodec.BufferInfo videoInfo = new MediaCodec.BufferInfo();
//beginTime指的是裁剪的开始时间,单位秒
mediaExtractor.seekTo(beginTime * 1000000, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
while(true){
int sampleSize = mediaExtractor.readSampleData(inputBuffer,0);
if(sampleSize<0){
mediaExtractor.unselectTrack(sourceVideoTrack);
break;
}
int trackIndex = mediaExtractor.getSampleTrackIndex();
//获取时间戳
long presentationTimeUs = mediaExtractor.getSampleTime();
//获取帧类型,只能识别是否为I帧
int sampleFlag = mediaExtractor.getSampleFlags();
//一定要填满 bufferInfo的参数
videoInfo.offset = 0;
videoInfo.size = sampleSize;
videoInfo.flags = sampleFlag;
videoInfo.presentationTimeUs=Math.round((presentationTimeUs) * isChangeSpeed);
//真正在这里写数据,videoTrackIndex就是addTrack返回的值
//inputBuffer是从extractor中read出来的数据
//videoinfo就是关于这个buffer的信息
mediaMuxer.writeSampleData(videoTrackIndex, inputBuffer, videoInfo);
mediaExtractor.advance();
}
(2)音频部分
mediaExtractor.selectTrack(sourceAudioTrack);
MediaCodec.BufferInfo audioInfo = new MediaCodec.BufferInfo();
mediaExtractor.seekTo(beginTime * 1000000, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
while(true){
int sampleSize = mediaExtractor.readSampleData(inputBuffer,0);
if(sampleSize<0){
mediaExtractor.unselectTrack(sourceAudioTrack);
break;
}
int trackIndex = mediaExtractor.getSampleTrackIndex();
//获取时间戳
long presentationTimeUs = mediaExtractor.getSampleTime();
//获取帧类型,只能识别是否为I帧
int sampleFlag = mediaExtractor.getSampleFlags();
audioInfo.offset = 0;
audioInfo.size = sampleSize;
audioInfo.flags = sampleFlag;
audioInfo.presentationTimeUs=presentationTimeUs;
mediaMuxer.writeSampleData(audioTrackIndex, inputBuffer, audioInfo);
mediaExtractor.advance();
}
4.释放资源
mediaMuxer.stop();
mediaMuxer.release();
mediaExtractor.release();
mediaExtractor = null;