Pcm 转 AAc

# Pcm 转 AAc

什么是Pcm?

PCM(Pulse Code Modulation)脉冲编码调制是数字通信的编码方式之一。主要过程是将话音、图像等模拟信号每隔一定时间进行取样,使其离散化,同时将抽样值按分层单位四舍五入取整量化,同时将抽样值按一组二进制码来表示抽样脉冲的幅值。

# Pcm 音频格式

PCM:其数据排列格式为左右声道每个样本点数据交错排列

一般来说,在做接收机开发的时候,考虑到网络传输负荷的问题,会考虑将音频(数据)信号进行下采样或者去噪的基
本处理,这样就要涉及到音频信号的滤波处理。但是不论是在时域滤波还是频域滤波,接收机直接输出的音频byte流不
能直接用,这时就要考虑用byte流恢复原始音频时域数据,这时必须清楚PCM编码的数据组织格式,涉及两个基本问题
一个pcm采样数据占多少字节,高低位存放顺序的问题,得到时域数据后才能使用滤波器对音频数据进行滤波,经过这
样的转换成功实现了音频信号中干扰噪声的滤波,使得音频更加清晰完全听不到干扰信号。

# AAC

aac 是音频文件的一种格式

# MP3和AAC有什么不同?

1、压缩技术的不同
MP3是利用人耳对高频声音信号不敏感的特性,将时域波形信号转换成频域信号,并划分成多个频段,对不同的频段使用不同的压缩率,对高频加大压缩比(甚至忽略信号)对低频信号使用小压缩比,保证信号不失真。
这样一来就相当于抛弃人耳基本听不到的高频声音,只保留能听到的低频部分,从而将声音用1∶10甚至1∶12的压缩率压缩。

AAC它采用了全新的算法进行编码,更加高效,具有更高的“性价比”。利用AAC格式,可使人感觉声音质量没有明显降低的前提下,更加小巧。

2、音频质量不同
AAC格式在96Kbps码率的表现超过了128Kbps的MP3格式。同样是128Kbps,AAC格式的音质明显好于MP3。AC是唯一一个,能够在所有的EBU试听测试项目的获得“优秀”的网络广播格式。

# 百度语音识别

最近开发上遇到一个功能 就是采用语音识别 将语音转换为文字 同时在转换完毕后要保留 文字信息和语音信息 文字间断输入 语音文件拼接 最后获取一串文字 和 一个.aac 文件

如何操作?

百度语音识别 移动文档

查找百度语音识别 文档发现 百度语音识别 语音转文字语音采集音频格式 如下:

默认为麦克风输入,可以设置参数为pcm格式16k采样率,16bit,小端序,单声道的音频流输入。

获取 百度语音识别 产生的音频文件:

/**
     * 基于SDK集成2.2 发送开始事件
     * 点击开始按钮
     * 测试参数填在这里
     */
    public void start() {

        Map<String, Object> params = new LinkedHashMap<String, Object>();
        String event = null;
        event = SpeechConstant.ASR_START; // 替换成测试的event

        if (enableOffline) {
            params.put(SpeechConstant.DECODER, 2);
        } else {

        }
        // 基于SDK集成2.1 设置识别参数
        params.put(SpeechConstant.ACCEPT_AUDIO_VOLUME, false); //当前音量回调
        //在联网情况下,在普通话的搜索模型或远场模型时可以使用,将识别出来的文本百度服务端做语义分析,获取文本的意图和词槽。
        params.put(SpeechConstant.PID, 15373); // 中文输入法模型,有逗号
        params.put(SpeechConstant.VAD_ENDPOINT_TIMEOUT, 3000); //开启长语音。开启VAD尾点检测,即静音判断的毫秒数。建议设置800ms-3000ms
        // params.put(SpeechConstant.NLU, "enable");
        params.put(SpeechConstant.DISABLE_PUNCTUATION, false);
        // params.put(SpeechConstant.IN_FILE, "res:///com/baidu/android/voicedemo/16k_test.pcm");
        params.put(SpeechConstant.VAD, SpeechConstant.VAD_DNN);
        //是否输出语音文件
        params.put(SpeechConstant.ACCEPT_AUDIO_DATA, true);
        //输出文件目录
        params.put(SpeechConstant.OUT_FILE, voicePcmUrl + "outfile.pcm");
        // 请先使用如‘在线识别’界面测试和生成识别参数。 params同ActivityRecog类中myRecognizer.start(params);
        // 复制此段可以自动检测错误
        (new AutoCheck(mContext, new Handler() {
            public void handleMessage(Message msg) {
                if (msg.what == 100) {
                    AutoCheck autoCheck = (AutoCheck) msg.obj;
                    synchronized (autoCheck) {
                        String message = autoCheck.obtainErrorMessage(); // autoCheck.obtainAllMessage();
                    }
                }
            }
        }, enableOffline)).checkAsr(params);
        String json = null; // 可以替换成自己的json
        json = new JSONObject(params).toString(); // 这里可以替换成你需要测试的json
        wakeup.send(event, json, null, 0, 0);
    }

既然拿到了.pcm 文件 那么问题来了 如何将pcm 转换为AAc 且完成拼接呢?

一阵疯狂的csdn 百度 官方文档 等等。。。

Android pcm 转 aac 实现方法

  • MediaCodec 配置编译器 实现编辑转码
  • ffmpeg

Android MediaCodec 基础原理

# 封装一个工具类:

  • 获取转化文件路径 转化完成输出文件保存路径
  • 初始化MediaCodec 编码器
  • 将.pcm bayte[] 数据存入 缓存队列
  • 开启一个线程 读取缓存队列数据开始转换
  • 转换监听
 /**
     * 设置输入输出文件位置
     *
     * @param srcPath
     * @param dstPath
     */
    public void setIOPath(String srcPath, String dstPath) {
        this.srcPath = srcPath;
        this.dstPath = dstPath;
    }
 /**
     * 此类已经过封装
     * 调用prepare方法 会初始化Decode 、Encode 、输入输出流 等一些列操作
     */
    public void prepare() {
        codeOver = false;
        if (srcPath == null) {
            throw new IllegalArgumentException("srcPath can't be null");
        }
        if (dstPath == null) {
            throw new IllegalArgumentException("dstPath can't be null");
        }
        try {
            File file = new File(srcPath);
            fileTotalSize = file.length();
            outFile = new File(dstPath);
            if (!file.exists()) {
                file.createNewFile();
            }
            fileOutSize = outFile.length();
            //            fos = new FileOutputStream(outFile);
            //            bos = new BufferedOutputStream(fos, (int) fileTotalSize);
            queue = new ArrayBlockingQueue<byte[]>(10);
            initAACMediaEncode();//AAC编码器
            FileInputStream inputStream = new FileInputStream(file);
            int available = inputStream.available();
            byte[] pcm = new byte[available];
            inputStream.read(pcm);
            putPCMData(pcm);
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 初始化AAC编码器
     */
    private void initAACMediaEncode() {
        try {
            LogUtils.d(key_bit_rate + " " + key_channel_count + " " + key_sample_rate + " " + sampleRateType);
            key_sample_rate = 16000;
            key_channel_count = 1;
            key_bit_rate = 16;
            sampleRateType = ADTSUtils.getSampleRateType(16000);
            MediaFormat encodeFormat = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC,
                    key_sample_rate, key_channel_count);//参数对应-> mime type、采样率、声道数
            encodeFormat.setInteger(MediaFormat.KEY_BIT_RATE, key_bit_rate);//比特率
            encodeFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
            encodeFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, (int) fileTotalSize);
            mediaEncode = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);
            mediaEncode.configure(encodeFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (mediaEncode == null) {
            LogUtils.e("create mediaEncode failed");
            return;
        }
        mediaEncode.start();
        encodeInputBuffers = mediaEncode.getInputBuffers();
        encodeOutputBuffers = mediaEncode.getOutputBuffers();
        encodeBufferInfo = new MediaCodec.BufferInfo();
    }
    
    /**
 * Author : eric
 * CreateDate : 2018/1/4  15:28
 * Email : ericli_wang@163.com
 * Version : 2.0
 * Desc :
 * Modified :
 */

public class ADTSUtils {
    private static Map<String, Integer> SAMPLE_RATE_TYPE;

    static {
        SAMPLE_RATE_TYPE = new HashMap<>();
        SAMPLE_RATE_TYPE.put("96000", 0);
        SAMPLE_RATE_TYPE.put("88200", 1);
        SAMPLE_RATE_TYPE.put("64000", 2);
        SAMPLE_RATE_TYPE.put("48000", 3);
        SAMPLE_RATE_TYPE.put("44100", 4);
        SAMPLE_RATE_TYPE.put("32000", 5);
        SAMPLE_RATE_TYPE.put("24000", 6);
        SAMPLE_RATE_TYPE.put("22050", 7);
        SAMPLE_RATE_TYPE.put("16000", 8);
        SAMPLE_RATE_TYPE.put("12000", 9);
        SAMPLE_RATE_TYPE.put("11025", 10);
        SAMPLE_RATE_TYPE.put("8000", 11);
        SAMPLE_RATE_TYPE.put("7350", 12);
    }

    public static int getSampleRateType(int sampleRate) {
        return SAMPLE_RATE_TYPE.get(sampleRate + "");
    }
}
    
    /**
     * 开始转码
     * 音频数据{@link #srcPath}先解码成PCM  PCM数据在编码成MediaFormat.MIMETYPE_AUDIO_AAC音频格式
     * mp3->PCM->aac
     */
    public void startAsync() {
        LogUtils.w("start");
        new Thread(new EncodeRunnable()).start();
    }
/**
     * 编码PCM数据 得到MediaFormat.MIMETYPE_AUDIO_AAC格式的音频文件,并保存到{@link #dstPath}
     */
    private void dstAudioFormatFromPCM() {

        int inputIndex;
        ByteBuffer inputBuffer;
        int outputIndex;
        ByteBuffer outputBuffer;
        byte[] chunkAudio;
        int outBitSize;
        int outPacketSize;
        byte[] chunkPCM;

        for (int i = 0; i < encodeInputBuffers.length - 1; i++) {
            chunkPCM = getPCMData();//获取解码器所在线程输出的数据 代码后边会贴上
            if (chunkPCM == null) {
                break;
            }
            inputIndex = mediaEncode.dequeueInputBuffer(-1);//同解码器
            inputBuffer = encodeInputBuffers[inputIndex];//同解码器
            inputBuffer.clear();//同解码器
            inputBuffer.limit(chunkPCM.length);
            inputBuffer.put(chunkPCM);//PCM数据填充给inputBuffer
            mediaEncode.queueInputBuffer(inputIndex, 0, chunkPCM.length, 0, 0);//通知编码器 编码
        }

        outputIndex = mediaEncode.dequeueOutputBuffer(encodeBufferInfo, 10000);//同解码器
        while (outputIndex >= 0) {//同解码器
            outBitSize = encodeBufferInfo.size;
            outPacketSize = outBitSize + 7;//7为ADTS头部的大小
            outputBuffer = encodeOutputBuffers[outputIndex];//拿到输出Buffer
            outputBuffer.position(encodeBufferInfo.offset);
            outputBuffer.limit(encodeBufferInfo.offset + outBitSize);
            chunkAudio = new byte[outPacketSize];
            addADTStoPacket(chunkAudio, outPacketSize);//添加ADTS 代码后面会贴上
            outputBuffer.get(chunkAudio, 7, outBitSize);//将编码得到的AAC数据 取出到byte[]中 偏移量offset=7 你懂得
            outputBuffer.position(encodeBufferInfo.offset);
            try {
                //实现追加
                RandomAccessFile randomFile = new RandomAccessFile(dstPath, "rw");
                // 文件长度,字节数
                long fileLength = randomFile.length();
                // 将写文件指针移到文件尾。
                randomFile.seek(fileLength);
                randomFile.write(chunkAudio, 0, chunkAudio.length);
                LogUtils.d("write " + chunkAudio.length);
                randomFile.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mediaEncode.releaseOutputBuffer(outputIndex, false);
            outputIndex = mediaEncode.dequeueOutputBuffer(encodeBufferInfo, 10000);
            codeOver = true;
        }
    }

    /**
     * 添加ADTS头
     *
     * @param packet
     * @param packetLen
     */
    private void addADTStoPacket(byte[] packet, int packetLen) {
        int profile = 2; // AAC LC
        int freqIdx = sampleRateType; // 44.1KHz
        int chanCfg = 2; // CPE


        // fill in ADTS data
        packet[0] = (byte) 0xFF;
        packet[1] = (byte) 0xF9;
        packet[2] = (byte) (((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2));
        packet[3] = (byte) (((chanCfg & 3) << 6) + (packetLen >> 11));
        packet[4] = (byte) ((packetLen & 0x7FF) >> 3);
        packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);
        packet[6] = (byte) 0xFC;
    }

注明:参考

AndroidMultiMedia

PCM编码后的音频数据存放格式说明

PCM音频格式的深入理解

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java是一种广泛应用于软件开发中的编程语言,而FAAC是一款常用的开源编码器,可以将PCM(脉冲编码调制)格式的音频换成AAC(高级音频编码)格式。下面是一种使用Java和FAAC库进行PCMAAC的简单示例。 首先,需要在Java项目中引入FAAC库的依赖。可以通过Maven等构建工具来添加FAAC库的依赖项。然后,在Java代码中调用FAAC库提供的方法来实现PCMAAC的功能。 ```java import com.googlecode.mp4parser.authoring.Sample; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.ShortBuffer; import java.util.ArrayList; public class PCM2AACConverter { // PCMAAC的方法 public static void pcmToAac(String inputPath, String outputPath) { try { FileInputStream fis = new FileInputStream(inputPath); FileOutputStream fos = new FileOutputStream(outputPath); int channels = 2; // 音频通道数 int sampleRate = 44100; // 采样率 int bitRate = 128000; // 码率 // 创建FAAC编码器 com.googlecode.mp4parser.authoring.Sample sample = new com.googlecode.mp4parser.authoring.Sample(); sample.begin(channels, sampleRate, bitRate); byte[] data = new byte[1024]; int bytesRead = 0; while ((bytesRead = fis.read(data)) > 0) { // 将PCM数据换成short类型的数组 ShortBuffer shortBuffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); short[] pcmData = new short[shortBuffer.remaining()]; shortBuffer.get(pcmData); // 将PCM数据添加到FAAC编码器 sample.add(pcmData); } // 完成PCM数据添加操作 sample.end(); // 获取AAC编码后的数据 ArrayList<byte[]> aacData = sample.getAACData(); // 将AAC数据写入输出文件 for (byte[] aacFrame : aacData) { fos.write(aacFrame); } fis.close(); fos.close(); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { String inputPath = "input.pcm"; // 输入PCM文件的路径 String outputPath = "output.aac"; // 输出AAC文件的路径 pcmToAac(inputPath, outputPath); } } ``` 上述代码使用了FAAC库提供的`Sample`类来进行PCMAAC操作。通过`pcmToAac`方法,将输入的PCM文件换成AAC格式并输出到指定路径。在此过程中,需要指定音频的通道数、采样率和码率等参数。 要使用上述方法,首先需要确保Java项目已经引入FAAC库的依赖,同时将输入的PCM文件和输出的AAC文件放置在正确的路径下。 以上是一个简单的示例,仅供参考。实际应用中,可能需要根据具体需求对代码进行修改和优化。 ### 回答2: Java FAAC PCMAAC可以通过使用FAAC库和Java编程语言来实现。以下是一个简单的示例代码来演示如何使用Java FAAC库将PCM音频文件换为AAC格式: ```java import com.googlecode.faac.Faac; import com.googlecode.faac.FaacConfig; import com.googlecode.faac.FaacConfigParams; import com.googlecode.faac.FaacInstance; public class PCMtoAACConverter { public static void main(String[] args) { String pcmFile = "input.pcm"; String aacFile = "output.aac"; // 初始化FAAC库 Faac faac = Faac.getInstance(); // 创建FAAC实例 FaacInstance faacInstance = faac.faacEncOpenDefault(48000, 2); // 设置FAAC配置参数 FaacConfig faacConfig = faac.faacEncGetCurrentConfiguration(faacInstance); FaacConfigParams configParams = new FaacConfigParams(); configParams.setBitrate(128000); configParams.setInputFormat(Faac.FAAC_INPUT_FORMAT_16BIT); faacConfig.setParams(configParams); faac.faacEncSetConfiguration(faacInstance, faacConfig); // 打开PCM文件和AAC文件 faac.faacEncOpenFile(faacInstance, pcmFile, aacFile); // 开始换 faac.faacEncEncode(faacInstance); // 关闭文件和FAAC实例 faac.faacEncClose(faacInstance); faac.faacEncCloseFile(faacInstance); System.out.println("PCMAAC完成!"); } } ``` 上述代码示例使用了FAAC库提供的相关函数来实现PCM文件换为AAC文件的功能。其中,需先准备好待换的PCM音频文件和指定的输出AAC文件路径。代码中的配置参数可根据需求进行调整,例如比特率、通道数等。 需要注意的是,使用FAAC库需要先下载并导入合适的FAAC库文件到项目中,并进行相关的配置。此外,FAAC库是一个开源的第三方库,使用时需了解其许可证限制和相关文档。 ### 回答3: 要使用Java将PCM音频文件换为AAC格式,可以使用FAAC库。FAAC是一个用于将音频文件编码为AAC格式的开源库。 首先,需要确保已经下载并安装了FAAC库。然后,可以在Java项目中使用JNI(Java Native Interface)来调用FAAC库的功能。 在Java中使用JNI调用FAAC库时,可以使用JNIWrapper库。这个库提供了一种方便的方式来与C/C++代码进行交互。 首先,需要编写一个调用FAAC的Java类。在这个类中,可以使用JNIWrapper库提供的函数来加载FAAC库和调用它的函数。可以编写一个Java方法来将PCM文件换为AAC文件。 示例代码如下: ```java import com.jniwrapper.*; import com.jniwrapper.win32.jni.*; import com.jniwrapper.util.*; public class FaacConverter { private static final String LIBRARY_NAME = "your_FAAC_library_name"; static { NativeLibraryLoader.loadLibrary(LIBRARY_NAME); } public static native int convertPcmToAac(String pcmFilePath, String aacFilePath); public static void main(String[] args) { String pcmFilePath = "/path/to/pcm/file.pcm"; String aacFilePath = "/path/to/aac/file.aac"; int result = convertPcmToAac(pcmFilePath, aacFilePath); if (result == 0) { System.out.println("PCM file converted to AAC successfully."); } else { System.out.println("Failed to convert PCM file to AAC."); } } } ``` 要使用这个示例代码,需要将FAAC库文件与Java项目一起编译,并将LIBRARY_NAME变量设置为FAAC库的名称。 编写完Java类后,可以使用Java编译器将其编译为可执行的Java程序。 然后,可以通过运行这个程序来将PCM文件换为AAC文件。在main方法中,可以设置PCM文件的路径和要生成的AAC文件的路径。 运行这个程序后,如果换成功,将会在控制台打印出"PCM file converted to AAC successfully."的消息,否则将会打印出"Failed to convert PCM file to AAC."的消息。 这就是使用Java将PCM音频文件换为AAC格式的基本步骤。希望对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值