一.主要使用的方法
MediaExtractor
1.setDataSource(String path)
设置数据源
2.getTrackFormat(int index)
获取指定索引通道的数据配置参数
3.selectTrack(int index)
选择轨道
4. getSampleTime()
获取当前pts时间戳,获取不到这返回-1
5.readSampleData(@NonNull ByteBuffer byteBuf, int offset)
数据存到缓存区byteBuf
6. advance()
释放上一帧数据
MediaMuxer
1.构造方法MediaMuxer( String path, int format)
初始化一个视频封装容器
2.addTrack(MediaFormat format)
添加指定格式通道
3.start()
开始合成
4. writeSampleData(int trackIndex, ByteBuffer byteBuf,BufferInfo bufferInfo)
将编码写入容器
二.实现过程
1.申请外置卡权限
2.解析Mp4
@SuppressLint("WrongConstant")
public void decodeToPCM(String musicPath, String outPath) throws Exception {
//创建解压工具
MediaExtractor mediaExtractor = new MediaExtractor();
//设置数据源
mediaExtractor.setDataSource(musicPath);
//获取音频轨道
int audioTrack =selectTrack(mediaExtractor,true);
//选择音频轨道
mediaExtractor.selectTrack(audioTrack);
//得到配置信息
MediaFormat oriAudioFormat = mediaExtractor.getTrackFormat(audioTrack);
//缓存大小
int maxBufferSize = 100 * 1000;
if (oriAudioFormat.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
maxBufferSize = oriAudioFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
}
ByteBuffer buffer = ByteBuffer.allocateDirect(maxBufferSize);
MediaCodec mediaCodec = MediaCodec.createDecoderByType(oriAudioFormat.getString((MediaFormat.KEY_MIME)));
// 设置解码器信息
mediaCodec.configure(oriAudioFormat, null, null, 0);
File pcmFile = new File(outPath);
FileChannel writeChannel = new FileOutputStream(pcmFile).getChannel();
//开始解码
mediaCodec.start();
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
int outputBufferIndex = -1;
while (true) {
int decodeInputIndex = mediaCodec.dequeueInputBuffer(0);
if (decodeInputIndex >= 0) {
long sampleTimeUs = mediaExtractor.getSampleTime();
if (sampleTimeUs == -1) {//结束了
break;
}else if (sampleTimeUs > 6000000) {//截取一段
break;
}
// 数据存到缓冲区
info.size = mediaExtractor.readSampleData(buffer, 0);
info.presentationTimeUs = sampleTimeUs;//时间
info.flags = mediaExtractor.getSampleFlags();
// 下面放数据到content 到dsp解码
byte[] content = new byte[buffer.remaining()];
buffer.get(content);
// 解码
ByteBuffer inputBuffer = mediaCodec.getInputBuffer(decodeInputIndex);
inputBuffer.put(content);
mediaCodec.queueInputBuffer(decodeInputIndex, 0, info.size, info.presentationTimeUs, info.flags);
// 释放上一帧的压缩数据
mediaExtractor.advance();
}
outputBufferIndex = mediaCodec.dequeueOutputBuffer(info, 100_000);
while (outputBufferIndex>=0) {
ByteBuffer decodeOutputBuffer = mediaCodec.getOutputBuffer(outputBufferIndex);
writeChannel.write(decodeOutputBuffer);//pcm
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(info, 100_000);
}
}
writeChannel.close();
mediaExtractor.release();
mediaCodec.stop();
mediaCodec.release();
}
3.封装MP4
@SuppressLint("WrongConstant")
public boolean process(String musicPath, String outPath) throws IOException {
MediaExtractor mMediaExtractor = new MediaExtractor();
//设置音频数据源
mMediaExtractor.setDataSource(musicPath);
int mVideoTrackIndex = -1;
int framerate = 0;
//选择视频轨道
int videoIndex= selectTrack(mMediaExtractor,false);
//获取视频轨道
MediaFormat format = mMediaExtractor.getTrackFormat(videoIndex);
framerate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
//切换到视频通道
mMediaExtractor.selectTrack(videoIndex);
// 初始化一个视频封装容器
mMediaMuxer = new MediaMuxer(outPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
// 添加一个空的轨道 轨道格式取自 视频文件,跟视频所有信息一样
mVideoTrackIndex = mMediaMuxer.addTrack(format);
mMediaMuxer.start();
if (mMediaMuxer == null) {
return false;
}
int maxBufferSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
ByteBuffer buffer = ByteBuffer.allocate(maxBufferSize);
//封装容器添加视频轨道信息
while (true) {
long sampleTimeUs = mMediaExtractor.getSampleTime();
if (sampleTimeUs == -1) {
break;
}
if (sampleTimeUs < 20000) {
//设置一个时间,这个时间之前的数据丢弃
mMediaExtractor.advance();
continue;
}
if ( sampleTimeUs > 60000000) {
//大于这个时间结束解析
break;
}
// pts
info.presentationTimeUs = sampleTimeUs - 20000+600;
info.flags = mMediaExtractor.getSampleFlags();
// 读取视频文件的数据
info.size = mMediaExtractor.readSampleData(buffer, 0);
if (info.size < 0) {
break;
}
// 视频轨道
mMediaMuxer.writeSampleData(videoIndex, buffer, info);
mMediaExtractor.advance();
}
Log.i("TAG", "mixAudioTrack: 完成");
mMediaExtractor.release();
mMediaMuxer.stop();
mMediaMuxer.release();
return true;
}
结果
1.获取到PCM数据输出到outPath
2.截取一段MP4输出到outPath