概述
继续学习MediaExtractor和MediaMuxer,主要作用就是音视频的分离和合成,此篇博客仅作为笔记使用,以防之后忘记
MediaExtractor
这个类的主要作用是把音频数据和视频数据分离
主要的API
方法 | 描述 |
---|---|
setDataSource(String path) | 设置源文件,既可以是本地文件也可以是网络文件 |
getTrackCount() | 获取源文件的通道数 |
getTrackFormat(int index) | 获取指定index的通道格式 |
getSampleTime() | 以微秒为单位返回当前样本的呈现时间。 |
readSampleData(ByteBuffer byteBuf, int offset) | 把指定通道中的数据,按照偏移量读取到ByteBuffer中 |
advance() | 读取下一帧的数据 |
release() | 完成后释放资源 |
MediaMuxer
这个类的组要作用是生成音频视频文件,还可以把音频和视频文件合成一个音视频文件
主要的API
方法 | 描述 |
---|---|
MediaMuxer(String path, int format) | path:输出文件的名称,format:输出文件的格式 |
addTrack(MediaFormat format) | 添加通道,我们可以用MediaCodec.getOutpurForma() 或者Extractor.getTrackFormat(int index) 来获取MediaFormat ,也可以自己建 |
start() | 开始合成文件 |
writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo) | 把ByteBuffer的数据写入到文件中 |
stop() | 停止合成 |
release() | 释放资源 |
实战
MediaExtractor的使用
private void start() {
FileOutputStream videooutputStream = null;
FileOutputStream audiooutputStream = null;
MediaExtractor mediaExtractor = null;
try {
File videofile = new File("/sdcard/aaapcm/video.mp4");
File audiofile = new File("/sdcard/aaapcm/audio.pcm");
videooutputStream = new FileOutputStream(videofile);
audiooutputStream = new FileOutputStream(audiofile);
mediaExtractor = new MediaExtractor();
//设置源文件
mediaExtractor.setDataSource("/sdcard/aaapcm/text.mp4");
//获取通道数
int trackCount = mediaExtractor.getTrackCount();
int audio = -1;
int video = -1;
for (int i = 0; i < trackCount; i++) {
MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
String formatString = trackFormat.getString(MediaFormat.KEY_MIME);
Log.d("mmm", formatString);
//视频通道
if (formatString.startsWith("video/")) {
video = i;
Log.d("mmm", "视频" + video);
}
//音频通道
if (formatString.startsWith("audio/")) {
audio = i;
Log.d("mmm", "音频" + audio);
}
}
ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024);
//选择视频通道
mediaExtractor.selectTrack(video);
int i;
//拿到视频通道的数据,写入到文件
while ((i = mediaExtractor.readSampleData(byteBuffer, 0)) > 0) {
byte[] bytes = new byte[i];
byteBuffer.get(bytes);
videooutputStream.write(bytes);
byteBuffer.clear();
mediaExtractor.advance();
}
videooutputStream.close();
//选择音频通道
mediaExtractor.selectTrack(audio);
//拿到音频通道的数据并写入文件
while ((i = mediaExtractor.readSampleData(byteBuffer, 0)) > 0) {
byte[] bytes = new byte[i];
byteBuffer.get(bytes);
audiooutputStream.write(bytes);
byteBuffer.clear();
mediaExtractor.advance();
}
audiooutputStream.close();
Log.d("mmm", "分离结束");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (mediaExtractor != null) {
mediaExtractor.release();
}
}
}
这部分代码主要是分离源文件的音频和视频分别保存在俩个文件中,分离后的文件并不能播放,需要在次合成才行,下面继续看下分析可播放的音频和视频
MediaMuxer的使用
这个需要MediaMuxer和MediaExtractor配合使用
分离视频数据并合成到新的MP4文件,新的MP4可播放
public void video() {
MediaMuxer mediaMuxer = null;
try {
MediaExtractor mediaExtractor = new MediaExtractor();
//设置源文件
mediaExtractor.setDataSource("/sdcard/aaapcm/text.mp4");
//获取通道数
int trackCount = mediaExtractor.getTrackCount();
int videoTrackindex = -1;
int framerate = -1;
for (int i = 0; i < trackCount; i++) {
MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
String formatString = trackFormat.getString(MediaFormat.KEY_MIME);
//找到视频通道
if (formatString.startsWith("video/")) {
framerate = trackFormat.getInteger(MediaFormat.KEY_FRAME_RATE);
//选择视频通道
mediaExtractor.selectTrack(i);
//创建MediaMuxer
mediaMuxer = new MediaMuxer("/sdcard/aaapcm/video11.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
//添加通道
videoTrackindex = mediaMuxer.addTrack(trackFormat);
//开始合成
mediaMuxer.start();
break;
}
}
if (mediaMuxer == null) {
return;
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
bufferInfo.presentationTimeUs = 0;
ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024);
int i = 0;
//从源文件读取视频数据
while ((i = mediaExtractor.readSampleData(byteBuffer, 0)) > 0) {
bufferInfo.offset = 0;
bufferInfo.size = i;
bufferInfo.flags = mediaExtractor.getSampleFlags();
bufferInfo.presentationTimeUs += 1000 * 1000 / framerate;
//把读取到的视频数据重新合成到新的文件
mediaMuxer.writeSampleData(videoTrackindex, byteBuffer, bufferInfo);
mediaExtractor.advance();
}
mediaExtractor.release();
mediaMuxer.stop();
mediaMuxer.release();
Log.d("mmm", "分离视频结束");
} catch (IOException e) {
e.printStackTrace();
}
}
分离音频数据并合成到新的wav文件,新的wav可播放
public void audio() {
MediaMuxer mediaMuxer = null;
try {
MediaExtractor mediaExtractor = new MediaExtractor();
//添加源文件
mediaExtractor.setDataSource("/sdcard/aaapcm/text.mp4");
//获取通道数
int trackCount = mediaExtractor.getTrackCount();
int audioTrackindex = -1;
int framerate = -1;
for (int i = 0; i < trackCount; i++) {
MediaFormat trackFormat = mediaExtractor.getTrackFormat(i);
String formatString = trackFormat.getString(MediaFormat.KEY_MIME);
//找到音频通道
if (formatString.startsWith("audio/")) {
mediaExtractor.selectTrack(i);
//创建MediaMuxer
mediaMuxer = new MediaMuxer("/sdcard/aaapcm/video11.wav", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
//添加通道
audioTrackindex = mediaMuxer.addTrack(trackFormat);
//开始合成
mediaMuxer.start();
}
if (formatString.startsWith("video/")) {
framerate = trackFormat.getInteger(MediaFormat.KEY_FRAME_RATE);
break;
}
}
if (mediaMuxer == null) {
return;
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
bufferInfo.presentationTimeUs = 0;
ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024);
int i = 0;
//分离音频数据
while ((i = mediaExtractor.readSampleData(byteBuffer, 0)) > 0) {
bufferInfo.offset = 0;
bufferInfo.size = i;
bufferInfo.flags = mediaExtractor.getSampleFlags();
bufferInfo.presentationTimeUs += 1000 * 1000 / framerate;
//把分离的音频数据合成到新的文件
mediaMuxer.writeSampleData(audioTrackindex, byteBuffer, bufferInfo);
mediaExtractor.advance();
}
mediaExtractor.release();
mediaMuxer.stop();
mediaMuxer.release();
Log.d("mmm", "分离音频结束");
} catch (IOException e) {
e.printStackTrace();
}
}
把刚才分离出来的视频文件和音频文件重新合成为音视频文件
public void hecheng() {
try {
MediaExtractor videoExtractor = new MediaExtractor();
videoExtractor.setDataSource("/sdcard/aaapcm/video11.mp4");
int trackCount = videoExtractor.getTrackCount();
int framerate = 0;
MediaFormat videotrackFormat = null;
for (int i = 0; i < trackCount; i++) {
videotrackFormat = videoExtractor.getTrackFormat(i);
String formatString = videotrackFormat.getString(MediaFormat.KEY_MIME);
if (formatString.startsWith("video/")) {
videoExtractor.selectTrack(i);
framerate = videotrackFormat.getInteger(MediaFormat.KEY_FRAME_RATE);
}
}
MediaExtractor audioExtractor = new MediaExtractor();
audioExtractor.setDataSource("/sdcard/aaapcm/video11.wav");
MediaFormat audiotrackFormat = null;
int trackCount1 = audioExtractor.getTrackCount();
for (int i = 0; i < trackCount1; i++) {
audiotrackFormat = audioExtractor.getTrackFormat(i);
String formatString = audiotrackFormat.getString(MediaFormat.KEY_MIME);
if (formatString.startsWith("audio/")) {
audioExtractor.selectTrack(i);
}
}
MediaCodec.BufferInfo videobufferInfo = new MediaCodec.BufferInfo();
MediaCodec.BufferInfo audiobufferInfo = new MediaCodec.BufferInfo();
MediaMuxer mediaMuxer = new MediaMuxer("sdcard/aaapcm/hecheng.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
int writeAudioTrackIndex = mediaMuxer.addTrack(audiotrackFormat);
int writeVideoTrackIndex = mediaMuxer.addTrack(videotrackFormat);
mediaMuxer.start();
ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024);
int i;
while ((i = videoExtractor.readSampleData(byteBuffer, 0)) > 0) {
videobufferInfo.size = i;
videobufferInfo.offset = 0;
videobufferInfo.flags = videoExtractor.getSampleFlags();
videobufferInfo.presentationTimeUs += 1000 * 1000 / framerate;
mediaMuxer.writeSampleData(writeVideoTrackIndex, byteBuffer, videobufferInfo);
videoExtractor.advance();
}
while ((i = audioExtractor.readSampleData(byteBuffer, 0)) > 0) {
audiobufferInfo.size = i;
audiobufferInfo.offset = 0;
audiobufferInfo.flags = audioExtractor.getSampleFlags();
audiobufferInfo.presentationTimeUs += 1000 * 1000 / framerate;
mediaMuxer.writeSampleData(writeAudioTrackIndex, byteBuffer, audiobufferInfo);
audioExtractor.advance();
}
videoExtractor.release();
audioExtractor.release();
mediaMuxer.stop();
mediaMuxer.release();
Log.d("mmm", "合成完毕");
} catch (IOException e) {
e.printStackTrace();
}
}
参考
https://blog.csdn.net/zhi184816/article/details/52514138
https://www.cnblogs.com/renhui/p/7478527.html