目标:用MediaExtract将视频分离成可播放的视频文件和音频文件
主要步骤:
初始化MediaExtractor和MediaMuxer
设置视频源
获取视频的通道数,并找到音视频通道记录下来
切换到相应的信道,读取数据到bytebuffer
记录视频帧/音频帧的信息,使用mediaMuxer把帧数据写入文件
MediaExtractor的关键方法介绍:
(1).mediaExtractor.setDataSource(SDCARD_PATH + "/test.mp4")
该方法设置数据源
(2).mediaExtractor.getTrackCount()
获取通道数量
(3).mediaExtractor.selectTrack(videoIndex)
切换到指定通道
(4).mediaExtractor.readSampleData(byteBuffer, offset);
读取一帧的数据,offset是在数据在byteoffer中的偏移量
(5).mediaExtractor.advance()
跳到下一帧
MediaMuxerd的关键方法介绍:
(1).int index=mediaMuxer.addTrack(MediaFormat)
添加通道,返回值是通道编号
(2).mediaMuxer.writeSampleData(mux_index_video, byteBuffer, bufferInfo)
写入一帧的数据
个人对BufferInfo的理解:描述了buffer的一些基本信息,包括尺寸、偏移位、标志、时间戳
视频分离的主要代码(音频类似)
private void mediaExvideo() { mediaExtractor = new MediaExtractor(); int videoIndex = -1; try { mediaExtractor.setDataSource(SDCARD_PATH + "/test.mp4"); for (int i = 0; i < mediaExtractor.getTrackCount(); i++) { MediaFormat mediaFormat = mediaExtractor.getTrackFormat(i); String mimitype = mediaFormat.getString(MediaFormat.KEY_MIME); //取出视频信号 if (mimitype.startsWith("video")) { videoIndex = i; break; } } //切换到视频信号的信道 mediaExtractor.selectTrack(videoIndex); MediaFormat mediaFormat_mux = mediaExtractor.getTrackFormat(videoIndex); mediaMuxer = new MediaMuxer(SDCARD_PATH + "/out_put.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); //追踪此信道 int mux_index_video = mediaMuxer.addTrack(mediaFormat_mux); ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024); MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); mediaMuxer.start(); long videoSampleTime; //获取每帧的时间 { mediaExtractor.readSampleData(byteBuffer, 0); //跳过第一个 I 帧 if (mediaExtractor.getSampleFlags() == MediaExtractor.SAMPLE_FLAG_SYNC) mediaExtractor.advance(); mediaExtractor.readSampleData(byteBuffer, 0); long firstVideoPTS = mediaExtractor.getSampleTime(); mediaExtractor.advance(); mediaExtractor.readSampleData(byteBuffer, 0); long secondeVideoPTS = mediaExtractor.getSampleTime(); videoSampleTime = Math.abs(secondeVideoPTS - firstVideoPTS); Log.i(TAG, "videoSampleTime:" + videoSampleTime); } //重新切换此信道,不然跳过了3帧会导致帧数模糊 mediaExtractor.unselectTrack(videoIndex); mediaExtractor.selectTrack(videoIndex); mediaExtractor.readSampleData(byteBuffer, 0); //读取每一帧数据 while (true) { int readSampleSize = mediaExtractor.readSampleData(byteBuffer, 0); if (readSampleSize < 0) break; mediaExtractor.advance(); bufferInfo.size = readSampleSize; bufferInfo.offset = 0; bufferInfo.flags = mediaExtractor.getSampleFlags(); bufferInfo.presentationTimeUs += videoSampleTime; //写入帧的数据 mediaMuxer.writeSampleData(mux_index_video, byteBuffer, bufferInfo); } mediaMuxer.release(); mediaExtractor.release(); Log.i(TAG, "video extract finish"); } catch (IOException e) { e.printStackTrace(); }}
如何把分离后的音视频合成为新的视频:
思路:通过通道的切换来控制音频数据和视频数据的写入
参考资料: https://blog.csdn.net/u012248972/article/details/80915736