Android音视频任务列表之(四)——学习 Android 平台的 MediaExtractor 和 MediaMuxer API,知道如何解析和封装 mp4 文件

一.主要使用的方法

MediaExtractor

1.setDataSource(String path)

设置数据源

2.getTrackFormat(int index)

获取指定索引通道的数据配置参数

3.selectTrack(int index)

选择轨道

4. getSampleTime()

获取当前pts时间戳,获取不到这返回-1

5.readSampleData(@NonNull ByteBuffer byteBuf, int offset)

数据存到缓存区byteBuf

6. advance()

释放上一帧数据

MediaMuxer

1.构造方法MediaMuxer( String path, int format)

初始化一个视频封装容器

2.addTrack(MediaFormat format)

添加指定格式通道

3.start()

开始合成

4. writeSampleData(int trackIndex, ByteBuffer byteBuf,BufferInfo bufferInfo)

将编码写入容器

二.实现过程

1.申请外置卡权限

2.解析Mp4

   @SuppressLint("WrongConstant")
    public void decodeToPCM(String musicPath, String outPath) throws Exception {
    //创建解压工具
        MediaExtractor mediaExtractor = new MediaExtractor();
        //设置数据源
        mediaExtractor.setDataSource(musicPath);
        //获取音频轨道
        int audioTrack =selectTrack(mediaExtractor,true);
        //选择音频轨道
        mediaExtractor.selectTrack(audioTrack);
        //得到配置信息
        MediaFormat oriAudioFormat = mediaExtractor.getTrackFormat(audioTrack);
        //缓存大小
        int maxBufferSize = 100 * 1000;
        if (oriAudioFormat.containsKey(MediaFormat.KEY_MAX_INPUT_SIZE)) {
            maxBufferSize = oriAudioFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
        }
        ByteBuffer buffer = ByteBuffer.allocateDirect(maxBufferSize);
        MediaCodec mediaCodec = MediaCodec.createDecoderByType(oriAudioFormat.getString((MediaFormat.KEY_MIME)));
//        设置解码器信息 
        mediaCodec.configure(oriAudioFormat, null, null, 0);
        File pcmFile = new File(outPath);
        FileChannel writeChannel = new FileOutputStream(pcmFile).getChannel();
        //开始解码
        mediaCodec.start();
        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        int outputBufferIndex = -1;
        while (true) {
            int decodeInputIndex = mediaCodec.dequeueInputBuffer(0);
            if (decodeInputIndex >= 0) {
                long sampleTimeUs = mediaExtractor.getSampleTime();
                if (sampleTimeUs == -1) {//结束了
                    break;
                }else if (sampleTimeUs > 6000000) {//截取一段
                    break;
                }
//                数据存到缓冲区
                info.size = mediaExtractor.readSampleData(buffer, 0);
                info.presentationTimeUs = sampleTimeUs;//时间
                info.flags = mediaExtractor.getSampleFlags();
//                下面放数据到content  到dsp解码
                byte[] content = new byte[buffer.remaining()];
                buffer.get(content);
//                解码
                ByteBuffer inputBuffer = mediaCodec.getInputBuffer(decodeInputIndex);
                inputBuffer.put(content);
                mediaCodec.queueInputBuffer(decodeInputIndex, 0, info.size, info.presentationTimeUs, info.flags);
//                释放上一帧的压缩数据
                mediaExtractor.advance();
            }

            outputBufferIndex = mediaCodec.dequeueOutputBuffer(info, 100_000);
            while (outputBufferIndex>=0) {
                ByteBuffer decodeOutputBuffer = mediaCodec.getOutputBuffer(outputBufferIndex);
                writeChannel.write(decodeOutputBuffer);//pcm
                mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
                outputBufferIndex = mediaCodec.dequeueOutputBuffer(info, 100_000);
            }

        }
        writeChannel.close();
        mediaExtractor.release();
        mediaCodec.stop();
        mediaCodec.release();
    }

3.封装MP4

 @SuppressLint("WrongConstant")
    public boolean process(String musicPath, String outPath) throws IOException {
        MediaExtractor   mMediaExtractor = new MediaExtractor();
        //设置音频数据源
        mMediaExtractor.setDataSource(musicPath);
        int mVideoTrackIndex = -1;
        int framerate = 0;
        //选择视频轨道
        int videoIndex= selectTrack(mMediaExtractor,false);
        //获取视频轨道
        MediaFormat format = mMediaExtractor.getTrackFormat(videoIndex);
        framerate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
        //切换到视频通道
        mMediaExtractor.selectTrack(videoIndex);
        //        初始化一个视频封装容器
        mMediaMuxer = new MediaMuxer(outPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
        //        添加一个空的轨道  轨道格式取自 视频文件,跟视频所有信息一样
        mVideoTrackIndex = mMediaMuxer.addTrack(format);
        mMediaMuxer.start();
        if (mMediaMuxer == null) {
            return false;
        }
        int   maxBufferSize = format.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);

        MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
        ByteBuffer buffer = ByteBuffer.allocate(maxBufferSize);
        //封装容器添加视频轨道信息
        while (true) {
            long sampleTimeUs = mMediaExtractor.getSampleTime();
            if (sampleTimeUs == -1) {
                break;
            }
            if (sampleTimeUs < 20000) {
            //设置一个时间,这个时间之前的数据丢弃
                mMediaExtractor.advance();
                continue;
            }
            if (  sampleTimeUs > 60000000) {
              //大于这个时间结束解析
                break;
            }
//                pts
            info.presentationTimeUs = sampleTimeUs - 20000+600;
            info.flags = mMediaExtractor.getSampleFlags();
//                读取视频文件的数据
            info.size = mMediaExtractor.readSampleData(buffer, 0);
            if (info.size < 0) {
                break;
            }
//                视频轨道 
            mMediaMuxer.writeSampleData(videoIndex, buffer, info);
            mMediaExtractor.advance();
        }
        Log.i("TAG", "mixAudioTrack: 完成");
        mMediaExtractor.release();
        mMediaMuxer.stop();
        mMediaMuxer.release();
        return true;
    }
    

结果

1.获取到PCM数据输出到outPath
2.截取一段MP4输出到outPath

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值