Android——使用MediaExtractor、MediaMuxer去掉视频文件中的音频数据

it2025-05-23  8

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 重新解码和编码。

最新回复(0)