【Android】使用MediaExtractor、MediaMuxer去掉视频文件中的音频数据
2023-09-11 14:20:52 时间
1 简介
本文以 mp4 文件为例,讲解去音频操作。mp4 是一种视频封装的容器,里面包含音频(audio)和视频(video)数据,对应的数据编码格式分别为 aac 和 h264。在去音频过程中,主要使用到 MediaFormat、MediaExtractor、MediaMuxer,其作用如下:
- MediaFormat:用于存储视频轨或音频轨的信息(MIME、时长、帧率、比特率、关键帧间隔、视频宽高等);
- MediaExtractor:媒体分离器,用于分离音频和视频数据,并且能够遍历帧数据;
- MediaMuxer:媒体复合器,用于合成音频和视频数据。
(1)MediaFormat
//初始化
MediaFormat mediaFormat = new MediaFormat()
MediaFormat mediaFormat = mediaExtractor.getTrackFormat(i)
//获取MIME
String mime = mediaFormat.getString(MediaFormat.KEY_MIME)
//获取总时长(单位:微秒us)
long durationTime = mediaFormat.getLong(MediaFormat.KEY_DURATION)
//获取帧率
int frameRate = mediaFormat.getInteger(MediaFormat.KEY_FRAME_RATE)
//获取比特率
int bitRate = mediaFormat.getInteger(MediaFormat.KEY_BIT_RATE)
//获取视频宽度(像素:px)
int width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH)
//获取视频高度(像素:px)
int height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT)
//获取关键帧间隔(单位:秒)
int iFrameInterval = mediaFormat.getInteger(MediaFormat.KEY_I_FRAME_INTERVAL)
用户也可以调用 mediaFormat.setX()方法注入属性。
(2)MediaExtractor
//初始化
MediaExtractor mediaExtractor = new MediaExtractor()
//设置资源
setDataSource(String input_path)
mediaExtractor.setDataSource("/sdcard/Pictures/WeiXin/a.mp4")
//获取轨道数
mediaExtractor.getTrackCount()
//获取 mediaFormat
MediaFormat mediaFormat = mediaExtractor.getTrackFormat(index) //index为轨道编号
//选择轨道
mediaExtractor.selectTrack(index) //index为轨道编号
//读取1帧数据到buffer
int input_size = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE) //获取最大输入缓存大小
ByteBuffer buffer = ByteBuffer.allocate(input_size)
int sampleSize = mediaExtractor.readSampleData(buffer, offset) //offset一般取0
//读取下一帧数据
mediaExtractor.advance()
//定位到timeUs附近的关键帧
mediaExtractor.seekTo(timeUs, mode) //mode一般取 MediaExtractor.SEEK_TO_CLOSEST_SYNC
//释放资源
mediaExtractor.release()
(3)MediaMuxer
//初始化
MediaMuxer(String output_path, int format)
MediaMuxer mediaMuxer = new MediaMuxer("/sdcard/a.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
//添加轨道
int videoTrackIndex = mediaMuxer.addTrack(mediaFormat)
//开始合成文件
mediaMuxer.start()
//写入数据
writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo)
//释放资源
mediaMuxer.stop()
mediaMuxer.release()
2 案例
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
private void get_video() throws IOException {
String input_path = "/sdcard/Pictures/WeiXin/a.mp4"; //源视频素材
String output_path = "/sdcard/a.mp4"; //去音频后的素材
MediaExtractor mediaExtractor = new MediaExtractor();
mediaExtractor.setDataSource(input_path);
MediaMuxer mediaMuxer = new MediaMuxer(output_path, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
int input_size =0;
int videoTrackIndex = -1;
int count = mediaExtractor.getTrackCount(); //获取轨道数
for (int i = 0; i < count; i++) {
MediaFormat format = mediaExtractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/")) { // mp4为“video/avc”
input_size = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
mediaExtractor.selectTrack(i);
videoTrackIndex = mediaMuxer.addTrack(format);
break;
}
}
mediaMuxer.start();
int sampleSize = 0;
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
ByteBuffer buffer = ByteBuffer.allocate(input_size); //也可以设置为:500*1024
while ((sampleSize = mediaExtractor.readSampleData(buffer, 0)) > 0) {
info.offset = 0;
info.size = sampleSize;
info.flags = mediaExtractor.getSampleFlags();
info.presentationTimeUs = mediaExtractor.getSampleTime();
mediaMuxer.writeSampleData(videoTrackIndex, buffer, info); //写入数据
mediaExtractor.advance(); //下一帧
}
mediaExtractor.release();
mediaMuxer.stop();
mediaMuxer.release();
}
3 拓展
可以通过修改 BufferInfo 的 presentationTimeUs 属性,实现倍速导出视频,如下:
float speed = 3.0f; //播放速度
info.presentationTimeUs = (long)(mediaExtractor.getSampleTime()/speed);
mediaMuxer.writeSampleData(videoTrackIndex, buffer, info); //写入数据
特别注意:不要试图通过修改 BufferInfo 的 flags 属性改变帧标签(I帧、P帧、B帧),若想修改帧标签,需要使用 Mediacodec 重新解码和编码。
相关文章
- Android 数据库综述(一) 数据库片的升级与数据的迁移操作
- Android View的绘制流程简述 Android自定义View(一)
- 【Android】读取文件数据到byte数组,并将读出的数据写入文件中强制刷新
- android ListView内数据的动态添加与删除
- android教程
- Android USB转串口开发(hoho.android.usbserial串口库)
- Android 众多的布局属性详解
- 《Android 应用案例开发大全(第3版)》——第1章,第1.5节本书案例项目的导入
- 教你打造一个Android组件化开发框架
- Android Xfermode 实战 实现圆形、圆角图片
- Android应用程序组件Content Provider的共享数据更新通知机制分析
- Android xml资源文件中@、@android:type、@*、?、@+含义和区别
- Android创建JSON格式数据
- Android学习笔记之:android更新ui的几种经常用法
- android Bluetooth程序设计
- 开发一个android桌面
- Android播放透明视频(转载)
- [Android Studio]Android 数据存储--SQLite数据库存储
- Android 与 JS 交互数据上限(Base64图片传输问题)