这篇文章的目的主要是学习 Android 平台的 MediaExtractor 和 MediaMuxer API,知道如何解析和封装 mp4 文件。
一个音视频文件是包含音频和视频,Android 中可以通过 MediaExtractor API 把音频或视频给单独抽取出来,通过 MediaMuxer 合成新的视频。
MediaExtractor 的作用就是将音频和视频分离。
主要是以下几个步骤:
1、创建实例
1
| MediaExtractor mediaExtractor = new MediaExtractor();
|
2、设置数据源
1
| mediaExtractor.setDataSource(path);
|
3、获取数据源的轨道数,切换到想要的轨道
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int videoIndex = -1;
MediaFormat mediaFormat = null;
int trackCount = mediaExtractor.getTrackCount(); for (int i = 0; i < trackCount; i++) { MediaFormat format = mediaExtractor.getTrackFormat(i); String mimeType = format.getString(MediaFormat.KEY_MIME); if (mimeType.startsWith("video/")) { videoIndex = i; mediaFormat = format; break; } }
mediaExtractor.selectTrack(videoIndex);
|
4、对所需轨道数据循环读取读取每帧,进行处理
1 2 3 4 5 6 7 8 9 10 11 12 13
| while (true) { int readSampleSize = mediaExtractor.readSampleData(byteBuffer, 0); if (readSampleSize < 0) { mediaExtractor.unselectTrack(videoIndex); break; } ... ... mediaExtractor.advance(); }
|
5、完成后释放资源
1
| mediaExtractor.release();
|
MediaMuxer 的作用是生成音频或视频文件;还可以把音频与视频混合成一个音视频文件。
主要是以下几个步骤:
1、创建实例
1
| MediaMuxermediaMuxer = new MediaMuxer(path, format);
|
path: 输出文件的名称;format: 输出文件的格式,当前只支持 MP4 格式。
2、将音频轨或视频轨添加到 MediaMuxer,返回新的轨道
1
| int trackIndex = mediaMuxer.addTrack(videoFormat);
|
3、开始合成
4、循环将音频轨或视频轨的数据写到文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| while (true) { int readSampleSize = mediaExtractor.readSampleData(byteBuffer, 0); if (readSampleSize < 0) { mediaExtractor.unselectTrack(videoIndex); break; } bufferInfo.size = readSampleSize; bufferInfo.flags = mediaExtractor.getSampleFlags(); bufferInfo.offset = 0; bufferInfo.presentationTimeUs = mediaExtractor.getSampleTime(); mediaMuxer.writeSampleData(trackIndex, byteBuffer, bufferInfo); mediaExtractor.advance(); }
|
5、完成后释放资源
1 2
| mediaMuxer.stop(); mediaMuxer.release();
|
实例
从 MP4 文件中分离出视频生成无声视频文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
|
private void extractVideo() { MediaExtractor mediaExtractor = new MediaExtractor(); MediaMuxer mediaMuxer = null; File fileDir = FileUtil.getExternalAssetsDir(this); try { mediaExtractor.setDataSource(new File(fileDir, VIDEO_SOURCE).getAbsolutePath()); int videoIndex = -1; MediaFormat mediaFormat = null; int trackCount = mediaExtractor.getTrackCount(); for (int i = 0; i < trackCount; i++) { MediaFormat format = mediaExtractor.getTrackFormat(i); String mimeType = format.getString(MediaFormat.KEY_MIME); if (mimeType.startsWith("video/")) { videoIndex = i; mediaFormat = format; break; } } mediaExtractor.selectTrack(videoIndex); File outFile = new File(FileUtil.getMuxerAndExtractorDir(this), OUTPUT_VIDEO); if (outFile.exists()) { outFile.delete(); } mediaMuxer = new MediaMuxer(outFile.getAbsolutePath(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); int trackIndex = mediaMuxer.addTrack(mediaFormat); ByteBuffer byteBuffer = ByteBuffer.allocate(mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)); MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); mediaMuxer.start(); while (true) { int readSampleSize = mediaExtractor.readSampleData(byteBuffer, 0); if (readSampleSize < 0) { mediaExtractor.unselectTrack(videoIndex); break; } bufferInfo.size = readSampleSize; bufferInfo.flags = mediaExtractor.getSampleFlags(); bufferInfo.offset = 0; bufferInfo.presentationTimeUs = mediaExtractor.getSampleTime(); mediaMuxer.writeSampleData(trackIndex, byteBuffer, bufferInfo); mediaExtractor.advance(); } Toast.makeText(this, "分离视频完成", Toast.LENGTH_SHORT).show(); } catch (IOException e) { e.printStackTrace(); } finally { if (mediaMuxer != null) { mediaMuxer.stop(); mediaMuxer.release(); } mediaExtractor.release(); } }
|
分离音频、合成音视频的代码类似,详见 GitHub :AndroidMultiMediaLearning
参考
1、Android 视频分离和合成(MediaMuxer和MediaExtractor)
2、Android 音视频开发(五):使用 MediaExtractor 和 MediaMuxer API 解析和封装 mp4 文件