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()
    }
相关推荐
鲸鱼爱泡芙5 小时前
FFMPEG3.0 增加RTSP拉取PCM音频流功能
ffmpeg·音视频·pcm
夏尔Gaesar23 天前
pcm | Parity Check Matrix(奇偶校验矩阵)
算法·矩阵·pcm
qq762118221 个月前
ffmpeg7.0 aac转pcm
c++·pcm·aac
EasyNVR1 个月前
EasyNVR平台现已支持AAC、G711A及G711U音频编码格式
数据库·安全·音视频·视频监控·aac·g711
苏三有春1 个月前
PyQt实战——将pcm文本数据转换成.pcm的二进制文件
python·pyqt·pcm
地方综合1 个月前
罗绰兰:以世界酒中国菜为翼,2024助力乡村振兴
g711
陪你去流浪_2 个月前
Vue 浏览器录音、播放、上传服务端(PCM 8000采样率 16位)
javascript·vue.js·pcm
aningxiaoxixi2 个月前
音频接口:PDM TDM128 TDM256
fpga开发·pcm
地方综合2 个月前
2024首届世界酒中国菜国际地理标志产品美食文化节成功举办篇章
g711