MediaExtractor、MediaMuxer 分离和合成 mp4

本文介绍了Android中利用MediaExtractor进行视频音频分离,以及MediaMuxer进行合成功能。在处理过程中,提到了MediaExtractor的setDataSource、getTrackCount等API,以及MediaMuxer的初始化、添加轨道和写入数据的方法。在实际操作中,遇到了presentationTimeUs计算的坑点,包括不能直接使用MediaExtractor.getSampleTime()以及在部分机型上MediaFormat.KEY_FRAME_RATE缺失的问题。为了解决这些问题,提出了根据帧率计算presentationTimeUs的方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

MediaExtractor

视音频分离器,将一些格式的视频分离出视频轨道和音频轨道。
主要流程,也是主要的 API:

  • setDataSource(String path):设置数据源
  • getTrackCount():获取通道数
  • getTrackFormat(int index):获取通道格式
  • readSampleData(ByteBuffer byteBuf, int offset):读取指定通道中的数据
  • getSampleTime():获取当前时间戳
  • advance():下一帧
  • release():释放资源
MediaMuxer

视音频合成器,将视频和音频合成相应的格式

  • MediaMuxer(String path, int format):初始化输出文件名称和输出文件的格式:mpeg4
  • addTrack(MediaFormat format):添加轨道,返回 track Index,会在 writeSampleData 中使用
  • start():开始合成文件
  • writeSampleData(int, ByteBuffer, MediaCodec.BufferInfo):写数据
  • stop():停止合成文件
  • release():释放资源
大体流程:

以下是分离 mp4 音频和视频的源码及注释:

    private String seperateMedia(String fileName, boolean isAudio) {
        String type = isAudio ? "audio/" : "video/";
        MediaExtractor mMediaExtractor = new MediaExtractor();;
        MediaMuxer mMediaMuxer = null;
        try {
            mMediaMuxer = new MediaMuxer(getSDPath() + "/" + fileName, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
            // 获取assert中的资源文件
            AssetFileDescriptor fileDescriptor = getAssetFileSource();
            // 设置资源文件
            mMediaExtractor.setDataSource(fileDescriptor.getFileDescriptor(), fileDescriptor.getStartOffset(), fileDescriptor.getLength());
            int mMediaIndex = 0;
            for (int i = 0; i < mMediaExtractor.getTrackCount(); i++) {
                //获取码流的详细格式/配置信息
                MediaFormat format = mMediaExtractor.getTrackFormat(i);
                String mine = format.getString(MediaFormat.KEY_MIME);
                // 查找音频:"audio/" 或者视频:"video/"的轨道
                if (mine.startsWith(type)) {
                    mMediaIndex = i;
                    break;
                }
            }
            // 选择感兴趣的轨道
            mMediaExtractor.selectTrack(mMediaIndex);
            // 获取通道格式,可以自己新建,但是有坑
            MediaFormat mediaFormat = mMediaExtractor.getTrackFormat(mMediaIndex);
            int muxerTrackIndex = mMediaMuxer.addTrack(mediaFormat);
            // 当采集视频的使用,需要获取帧率,音频轨道没有这个参数
            int framerate = isAudio ? 0 : mediaFormat.getInteger(MediaFormat.KEY_FRAME_RATE);
            mMediaMuxer.start();

            ByteBuffer byteBuffer = ByteBuffer.allocate(500 * 1024);
            int readSize = 0;
            // writeSampleData需要BufferInfo参数
            MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
            while((readSize = mMediaExtractor.readSampleData(byteBuffer, 0)) > 0) {
                bufferInfo.size = readSize;
                bufferInfo.flags = mMediaExtractor.getSampleFlags(); //设置为关键帧等
                bufferInfo.offset = 0;
                if (!isAudio) { // 时间戳,音频和视频的处理方式不一样
                    bufferInfo.presentationTimeUs += 1000 * 1000 / framerate;
                } else {
                    bufferInfo.presentationTimeUs = mMediaExtractor.getSampleTime();
                }
                mMediaMuxer.writeSampleData(muxerTrackIndex, byteBuffer, bufferInfo);
                Log.d("getSampleTime", "seperateMedia: " + mMediaExtractor.getSampleTime() );
                mMediaExtractor.advance(); 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值