利用MediaCodec将aac解码为pcm

完整代码:https://github.com/wuqingsen/AVWuDemo

目录:Android音视频整理

package com.demo.audiowudemo.util;

import android.annotation.SuppressLint;
import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.os.Environment;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
/**
 * wuqingsen on 2020-05-28
 * Mailbox:1243411677@qq.com
 * annotation:aac转pcm
 */
@SuppressLint("NewApi")
public class AACToPCM {
    //用于分离出音频轨道
    private MediaExtractor mMediaExtractor;
    private MediaCodec mMediaDecode;
    private File targetFile;
    //类型
    private String mime = "audio/mp4a-latm";
    //输入缓存组
    private ByteBuffer[] inputBuffers;
    //输出缓存组
    private ByteBuffer[] outputBuffers;
    private MediaCodec.BufferInfo bufferInfo;
    private File pcmFile;
    private FileOutputStream fileOutputStream;
    private int totalSize = 0;

    public AACToPCM(String aacPath, String pcmPath)
    {
        targetFile = new File(aacPath);
        pcmFile = new File(pcmPath);
        if (!pcmFile.exists()) {
            try {
                pcmFile.getParentFile().mkdirs();
                pcmFile.createNewFile();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            fileOutputStream = new FileOutputStream(pcmFile.getAbsoluteFile());
        } catch (Exception e) {
            e.printStackTrace();
        }
        mMediaExtractor = new MediaExtractor();
        try {
            //设置资源
            mMediaExtractor.setDataSource(targetFile.getAbsolutePath());
            //获取含有音频的MediaFormat
            MediaFormat mediaFormat = createMediaFormat();
            mMediaDecode = MediaCodec.createDecoderByType(mime);
            mMediaDecode.configure(mediaFormat, null, null, 0);//当解压的时候最后一个参数为0
            mMediaDecode.start();//开始,进入runnable状态
            //只有MediaCodec进入到Runnable状态后,才能过去缓存组
            inputBuffers = mMediaDecode.getInputBuffers();
            outputBuffers = mMediaDecode.getOutputBuffers();
            bufferInfo = new MediaCodec.BufferInfo();
        } catch (Exception e) {

            e.printStackTrace();
        }

    }

    private MediaFormat createMediaFormat() {
        //获取文件的轨道数,做循环得到含有音频的mediaFormat
        for (int i = 0; i < mMediaExtractor.getTrackCount(); i++) {
            MediaFormat mediaFormat = mMediaExtractor.getTrackFormat(i);
            //MediaFormat键值对应
            String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
            if (mime.contains("audio/")) {
                mMediaExtractor.selectTrack(i);
                return mediaFormat;
            }
        }
        return null;
    }


    public void decode() {
        boolean inputSawEos = false;
        boolean outputSawEos = false;
        long kTimes = 5000;//循环时间
        while (!outputSawEos) {
            if (!inputSawEos) {
                //每5000毫秒查询一次
                int inputBufferIndex = mMediaDecode.dequeueInputBuffer(kTimes);
                //输入缓存index可用
                if (inputBufferIndex >= 0) {
                    //获取可用的输入缓存
                    ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
                    //从MediaExtractor读取数据到输入缓存中,返回读取长度
                    int bufferSize = mMediaExtractor.readSampleData(inputBuffer, 0);
                    if (bufferSize <= 0) {//已经读取完
                        //标志输入完毕
                        inputSawEos = true;
                        //做标识
                        mMediaDecode.queueInputBuffer(inputBufferIndex, 0, 0, kTimes, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                    } else {
                        long time = mMediaExtractor.getSampleTime();
                        //将输入缓存放入MediaCodec中
                        mMediaDecode.queueInputBuffer(inputBufferIndex, 0, bufferSize, time, 0);
                        //指向下一帧
                        mMediaExtractor.advance();
                    }
                }
            }
            //获取输出缓存,需要传入MediaCodec.BufferInfo 用于存储ByteBuffer信息
            int outputBufferIndex = mMediaDecode.dequeueOutputBuffer(bufferInfo, kTimes);
            if (outputBufferIndex >= 0) {
                int id = outputBufferIndex;
                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                    mMediaDecode.releaseOutputBuffer(id, false);
                    continue;
                }
                //有输出数据
                if (bufferInfo.size > 0) {
                    //获取输出缓存
                    ByteBuffer outputBuffer = outputBuffers[id];
                    //设置ByteBuffer的position位置
                    outputBuffer.position(bufferInfo.offset);
                    //设置ByteBuffer访问的结点
                    outputBuffer.limit(bufferInfo.offset + bufferInfo.size);
                    byte[] targetData = new byte[bufferInfo.size];
                    //将数据填充到数组中
                    outputBuffer.get(targetData);
                    try {
                        fileOutputStream.write(targetData);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                //释放输出缓存
                mMediaDecode.releaseOutputBuffer(id, false);
                //判断缓存是否完结
                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                    outputSawEos = true;
                }
            } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
                outputBuffers = mMediaDecode.getOutputBuffers();

            }else if(outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED){
                MediaFormat  mediaFormat = mMediaDecode.getOutputFormat();
            }
        }
        //释放资源
        try {
            fileOutputStream.flush();
            fileOutputStream.close();
            mMediaDecode.stop();
            mMediaDecode.release();
            mMediaExtractor.release();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



}

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这里有一个简单的MediaCodec C++例子,可以将MP4文件解码为YUV格式: ```c++ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <media/NdkMediaCodec.h> #include <media/NdkMediaExtractor.h> #include <media/NdkMediaFormat.h> #define TIMEOUT_US 10000 int main(int argc, char **argv) { if (argc != 3) { fprintf(stderr, "Usage: %s <input.mp4> <output.yuv>\n", argv[0]); return -1; } // 创建MediaExtractor对象 AMediaExtractor *extractor = AMediaExtractor_new(); if (!extractor) { fprintf(stderr, "Failed to create MediaExtractor\n"); return -1; } // 设置数据源 if (AMediaExtractor_setDataSource(extractor, argv[1]) != AMEDIA_OK) { fprintf(stderr, "Failed to set data source '%s'\n", argv[1]); return -1; } // 获取视频轨道 AMediaFormat *format = NULL; int trackIndex = -1; for (int i = 0; i < AMediaExtractor_getTrackCount(extractor); i++) { format = AMediaExtractor_getTrackFormat(extractor, i); const char *mime; AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime); if (!strncmp(mime, "video/", 6)) { trackIndex = i; break; } } if (trackIndex == -1) { fprintf(stderr, "No video track found\n"); return -1; } // 选择视频轨道 AMediaExtractor_selectTrack(extractor, trackIndex); // 创建MediaCodec对象 AMediaCodec *decoder = AMediaCodec_createDecoderByType(AMediaFormat_toString(format)); if (!decoder) { fprintf(stderr, "Failed to create decoder for '%s'\n", AMediaFormat_toString(format)); return -1; } // 配置MediaCodec对象 AMediaCodec_configure(decoder, format, NULL, NULL, 0); // 启动MediaCodec对象 AMediaCodec_start(decoder); // 创建输出文件 FILE *fpOut = fopen(argv[2], "wb"); if (!fpOut) { fprintf(stderr, "Failed to create output file '%s'\n", argv[2]); return -1; } // 解码视频数据 ssize_t sampleSize = 0; uint8_t *inputBuffer = NULL; size_t inputBufferSize = 0; AMediaCodecBufferInfo inputBufferInfo; memset(&inputBufferInfo, 0, sizeof(inputBufferInfo)); bool sawInputEOS = false; bool sawOutputEOS = false; while (!sawOutputEOS) { // 从Extractor中获取输入数据 if (!sawInputEOS) { int inputBufferIndex = AMediaCodec_dequeueInputBuffer(decoder, TIMEOUT_US); if (inputBufferIndex >= 0) { inputBuffer = AMediaCodec_getInputBuffer(decoder, inputBufferIndex, &inputBufferSize); sampleSize = AMediaExtractor_readSampleData(extractor, inputBuffer, inputBufferSize); if (sampleSize < 0) { // 输入结束,发送EOS标志 AMediaCodec_queueInputBuffer(decoder, inputBufferIndex, 0, 0, 0, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM); sawInputEOS = true; } else { // 将数据提交给MediaCodec对象进行解码 AMediaCodec_queueInputBuffer(decoder, inputBufferIndex, 0, sampleSize, AMediaExtractor_getSampleTime(extractor), 0); AMediaExtractor_advance(extractor); } } } // 从MediaCodec中获取输出数据 AMediaCodecBufferInfo outputBufferInfo; uint8_t *outputBuffer = AMediaCodec_getOutputBuffer(decoder, &outputBufferInfo, TIMEOUT_US); if (outputBuffer) { // 将YUV数据保存到文件中 fwrite(outputBuffer, 1, outputBufferInfo.size, fpOut); // 释放输出缓冲区 AMediaCodec_releaseOutputBuffer(decoder, AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED, false); if ((outputBufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) != 0) { sawOutputEOS = true; } } else if (outputBuffer == NULL && sawInputEOS) { break; } } // 关闭输出文件 fclose(fpOut); // 停止并释放MediaCodec对象 AMediaCodec_stop(decoder); AMediaCodec_delete(decoder); // 释放MediaExtractor对象 AMediaExtractor_delete(extractor); return 0; } ``` 请注意,此示例仅用于演示如何使用MediaCodec C++将MP4文件解码为YUV格式。实际应用中,您需要根据您的具体需求进行适当的修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值