原文链接: https://juejin.cn/post/6978908459982913567
一个音视频文件是由音频和视频组成的,我们可以通过 MediaExtractor、MediaMuxer把音频或视频给 单独抽取出来,抽取出来的音频和视频能单独播放;
一、MediaExtractor API介绍
MediaExtractor的作用是把音频和视频的数据进行分离。
主要API介绍:
setDataSource(String path):即可以设置本地文件又可以设置网络文件
getTrackCount():得到源文件通道数
getTrackFormat(int index):获取指定(index)的通道格式
getSampleTime():返回当前的时间戳
readSampleData(ByteBuffer byteBuf, int offset):把指定通道中的数据按偏移量读取到ByteBuffer中;
advance():读取下一帧数据
release(): 读取结束后释放资源
使用示例:
private fun onMediaExtractor() {
val path =
Environment.getExternalStorageDirectory().absolutePath + File.separator + "test.mp4"
val extractor = MediaExtractor()
//1.设置数据源
extractor.setDataSource(path)
val numTracks = extractor.trackCount
ALog.e("xiao", "源文件通道数: $numTracks")
for (i in 0 until numTracks) {
ALog.e("xiao", "*******")
//2.分离轨道
val format = extractor.getTrackFormat(i)
val mine = format.getString(MediaFormat.KEY_MIME)
ALog.e("xiao", "mime: $mine")
//3.选择轨道
extractor.selectTrack(i)
val inputBuffer = ByteBuffer.allocate(format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE)) //获取视频缓存输出的最大大小
//4.读取数据
while (true) {
val readSampleDataSize = extractor.readSampleData(inputBuffer, 0)
if (readSampleDataSize < 0) break
ALog.e("xiao", "trackIndex: ${extractor.sampleTrackIndex}")
ALog.e("xiao", "presentationTimeUs: ${extractor.sampleTime}")
// 其他操作省略
//5.下一帧
extractor.advance()
}
}
//6.释放
extractor.release()
}
二、MediaMuxer API介绍
MediaMuxer的作用是生成音频或视频文件;还可以把音频与视频混合成一个音视频文件。
相关API介绍:
MediaMuxer(String path, int format):path:输出文件的名称 format:输出文件的格式;当前只支持MP4格式;
addTrack(MediaFormat format):添加通道;我们更多的是使用MediaCodec.getOutpurForma()或Extractor.getTrackFormat(int index)来获取MediaFormat;也可以自己创建;
start():开始合成文件
writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo):把
ByteBuffer中的数据写入到在构造器设置的文件中;
stop():停止合成文件
release():释放资源
使用示例:
val muxer = MediaMuxer(path, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
val audioFormat = MediaFormat(...)
val videoFormat = MediaFormat(...)
val audioTrackIndex = muxer.addTrack(audioFormat)
val videoTrackIndex = muxer.addTrack(videoFormat)
val inputBuffer = ByteBuffer.allocate(1024 * 8 *100) //随便填的一个,需要获取
val finished = false
val bufferInfo = BufferInfo()
muxer.start()
while(!finished) {
finished = getInputBuffer(inputBuffer, isAudioSample, bufferInfo);
if (!finished) {
val currentTrackIndex = if (isAudioSample) audioTrackIndex else videoTrackIndex
muxer.writeSampleData(currentTrackIndex, inputBuffer, bufferInfo);
}
}
muxer.stop();
muxer.release();
三、使用情境
3.1 从MP4文件中提取视频并生成新的视频文件
//从MP4文件中提取视频并生成新的视频文件
private fun ex(): Boolean {
requestPermissions.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
val sourcePath =
Environment.getExternalStorageDirectory().absolutePath + File.separator + "test.mp4"
val outputPath =
Environment.getExternalStorageDirectory().absolutePath + File.separator + "output.mp4"
val mediaExtractor = MediaExtractor()
var mediaMuxer: MediaMuxer? = null
mediaExtractor.setDataSource(sourcePath)
var videoTrackIndex = -1
var frameRate = 0
val numTracks = mediaExtractor.trackCount
for (i in 0 until numTracks) {
val format = mediaExtractor.getTrackFormat(i)
val mime = format.getString(MediaFormat.KEY_MIME) ?: continue
if (!mime.startsWith("video/")) {
continue
}
frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE)
mediaExtractor.selectTrack(i)
mediaMuxer = MediaMuxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
videoTrackIndex = mediaMuxer.addTrack(format)
mediaMuxer.start()
}
val _mediaMuxer = mediaMuxer ?: return false
val info = MediaCodec.BufferInfo()
info.presentationTimeUs = 0
val buffer = ByteBuffer.allocate(500 * 1024)
var sampleSize = 0
while (true) {
sampleSize = mediaExtractor.readSampleData(buffer, 0)
if (sampleSize <= 0) break
info.offset = 0
info.size = sampleSize
info.flags = MediaCodec.BUFFER_FLAG_KEY_FRAME
info.presentationTimeUs += 1000 * 1000 / frameRate
_mediaMuxer.writeSampleData(videoTrackIndex, buffer, info)
mediaExtractor.advance()
}
mediaExtractor.release()
_mediaMuxer.stop()
_mediaMuxer.release()
return true
}
源码地址:https://gitee.com/vvwwvv/video-practice.git
-- END --
进技术交流群,扫码添加我的微信:Byte-Flow
获取视频教程和源码
推荐: