PCM与G711A互转

PCM与G711A互转

工具类(Java)

复制代码
public class G711Code {
    private final static int SIGN_BIT = 0x80;
    private final static int QUANT_MASK = 0xf;
    private final static int SEG_SHIFT = 4;
    private final static int SEG_MASK = 0x70;
 
    static short[] seg_end = {0xFF, 0x1FF, 0x3FF, 0x7FF,0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
 
    static short search(short val,short[] table,short size){
        for (short i = 0 ; i < size; i++) {
            if(val <= table[i]){
                return i;
            }
        }
        return size;
    }
 
    static byte linear2alaw(short pcm_val){
        short mask;
        short seg;
        char aval;
        if(pcm_val >= 0){
            mask = 0xD5;
        }else{
            mask = 0x55;
            pcm_val = (short) (-pcm_val - 1);
            if(pcm_val < 0){
                pcm_val = 32767;
            }
        }
 
        /* Convert the scaled magnitude to segment number. */
        seg = search(pcm_val, seg_end, (short) 8);
 
        /* Combine the sign, segment, and quantization bits. */
 
        if (seg >= 8)       /* out of range, return maximum value. */
            return (byte) (0x7F ^ mask);
        else {
            aval = (char) (seg << SEG_SHIFT);
            if (seg < 2)
                aval |= (pcm_val >> 4) & QUANT_MASK;
            else
                aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
            return (byte) (aval ^ mask);
        }
    }
 
    static short alaw2linear(byte a_val){
        short       t;
        short       seg;
 
        a_val ^= 0x55;
 
        t = (short) ((a_val & QUANT_MASK) << 4);
        seg = (short) ((a_val & SEG_MASK) >> SEG_SHIFT);
        switch (seg) {
            case 0:
                t += 8;
                break;
            case 1:
                t += 0x108;
                break;
            default:
                t += 0x108;
                t <<= seg - 1;
        }
        return (a_val & SIGN_BIT) != 0 ? t : (short) -t;
    }
 
    /**
     * pcm 转 g711a
     * @param pcm
     * @param code
     * @param size
     */
    public static void G711aEncoder(short[] pcm,byte[] code,int size){
        for(int i=0;i<size;i++){
            code[i]=linear2alaw(pcm[i]);
//            Log.e("-------------","数据编码:"+code[i]);
        }
    }
 
    /**
     * g711a 转 pcm
     * @param pcm
     * @param code
     * @param size
     */
    public static void G711aDecoder(short[] pcm,byte[] code,int size){
        for(int i=0;i<size;i++){
            pcm[i]=alaw2linear(code[i]);
        }
    }

    /**
     * byte转short
     * @param data
     * @return
     */
    public static short[] byteToShort(byte[] data) {
        short[] shortValue = new short[data.length / 2];
        for (int i = 0; i < shortValue.length; i++) {
            shortValue[i] = (short) ((data[i * 2] & 0xff) | ((data[i * 2 + 1] & 0xff) << 8));
        }
        return shortValue;
    }

    /**
     * short转byte
     * @param data
     * @return
     */
    public static byte[] shortToByte(short[] data) {
        byte[] byteValue = new byte[data.length * 2];
        for (int i = 0; i < data.length; i++) {
            byteValue[i * 2] = (byte) (data[i] & 0xff);
            byteValue[i * 2 + 1] = (byte) ((data[i] & 0xff00) >> 8);
        }
        return byteValue;
    }
 
}

调用方法(Kotlin)

复制代码
	/**
     * ffmpeg -f s16le -i customAudio1.pcm -f alaw customAudio1.pcm.g711a
     * ffplay -f s16le -ar 8000 customAudio1.pcm
     * ffplay -f alaw -ar 8000 customAudio1.pcm.g711a
     *
     * 可以用进制软件比如hexviewer查看对比ffmpeg转化的g711a文件
     * 或者使用ffplay播放显示波形
     */
	fun pcm2g711a(){
        val inputStream: InputStream = assets.open("customAudio1.pcm")
        val available = inputStream.available()
        Log.e("TAG","available:"+available)
        val bytes: ByteArray = ByteArray(available)
        val byteCount = inputStream.read(bytes)
        Log.e("TAG","byteCount:"+byteCount)

        //文件大可能需要循环读取
//        val bytes: ByteArray = ByteArray(1024)
//        var byteCount = inputStream.read(bytes)
//        Log.e("TAG","start byteCount:"+byteCount)
//        while (byteCount != -1){
//            byteCount = inputStream.read(bytes)
//            Log.e("TAG","byteCount:"+byteCount)
//        }
//        Log.e("TAG","end byteCount:"+byteCount)

        val shortPCM: ShortArray = G711Code.byteToShort(bytes)//一定要转!!!
        val bytesG711A: ByteArray = ByteArray(available)
        Log.e("TAG","shortPCM.size:"+shortPCM.size)
        G711Code.G711aEncoder(shortPCM,bytesG711A,shortPCM.size)
        Log.e("TAG","bytesG711A.size:"+bytesG711A.size)

        val file = File(getExternalFilesDir(null)?.absolutePath+"/customAudio1_"+System.currentTimeMillis()+".g711a")
        val fos = FileOutputStream(file)
        fos.write(bytesG711A)
        Log.e("TAG","write end")

        inputStream.close()
        fos.flush()
        fos.close()
    }

    fun g711a2pcm(){
        val inputStream: InputStream = assets.open("customAudio1.pcm.g711a")
        val available = inputStream.available()
        Log.e("TAG","available:"+available)
        val bytes: ByteArray = ByteArray(available)
        val byteCount = inputStream.read(bytes)
        Log.e("TAG","byteCount:"+byteCount)

        //文件大可能需要循环读取
//        val bytes: ByteArray = ByteArray(1024)
//        var byteCount = inputStream.read(bytes)
//        Log.e("TAG","start byteCount:"+byteCount)
//        while (byteCount != -1){
//            byteCount = inputStream.read(bytes)
//            Log.e("TAG","byteCount:"+byteCount)
//        }
//        Log.e("TAG","end byteCount:"+byteCount)

//        val bytesPCMEmpty: ByteArray = ByteArray(available)
//        Log.e("TAG","bytesPCMEmpty.size:"+bytesPCMEmpty.size)
//        val shortPCM: ShortArray = G711Code.byteToShort(bytesPCMEmpty)//会丢失后面一段数据!!!
        val shortPCM: ShortArray = ShortArray(available)
        Log.e("TAG","shortPCM.size:"+shortPCM.size)
        G711Code.G711aDecoder(shortPCM,bytes,bytes.size)
        Log.e("TAG","shortPCM.size:"+shortPCM.size)

        val file = File(getExternalFilesDir(null)?.absolutePath+"/customAudio1_"+System.currentTimeMillis()+".pcm")
        val fos = FileOutputStream(file)
        val bytesPCM: ByteArray = G711Code.shortToByte(shortPCM)
        fos.write(bytesPCM)
        Log.e("TAG","write end")

        inputStream.close()
        fos.flush()
        fos.close()
    }
相关推荐
NO Exception?7 天前
完美解决 mobile-ffmpeg Not overwriting - exiting
android·ffmpeg·pcm
一路向北he12 天前
pcm数据不支持存储在json里面,需要先转base64
json·pcm
亦双城的双子娴13 天前
通过音频的pcm数据格式利用canvas绘制音频波形图
音视频·pcm·canva可画
CheungChunChiu20 天前
PCM 参数深度解析:采样率、帧、缓存大小与多通道关系
android·linux·嵌入式·pcm·通道·tinyalsa·音频开发
Antonio91523 天前
【音视频】SDL播放PCM音频
ffmpeg·音视频·pcm
Json____1 个月前
springboot 处理编码的格式为opus的音频数据解决方案【java8】
spring boot·后端·音视频·pcm·音频处理·解码器·opus
Liu-Eleven2 个月前
嵌入式音频框架alsa学习之pcm状态
学习·音视频·pcm
byxdaz2 个月前
QT编程之PCM音频处理
音视频·pcm
【ql君】qlexcel2 个月前
电动自行车/电动工具锂电池PCM方案--SH367003、SH367004、SH79F329
pcm·bms·锂电池
【ql君】qlexcel2 个月前
笔记本电脑电池PCM方案介绍--中颖SH366000
电脑·pcm·bms·中颖·sh366000