G711 A-law和原始PCM转化

908 阅读1分钟
package com.cms.common.utils;

import cn.hutool.core.util.ByteUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * G711 A-law和原始PCM转化
 *
 * @author yangjianbin
 * @since 2022/10/26 13:57
 */
public class ALawCodec {

    /* Sign bit for a A-law byte. */
    private final static int SIGN_BIT = 0x80;
    /* Quantization field mask. */
    private final static int QUANT_MASK = 0xF;
    /* Left shift for segment number. */
    private final static int SEG_SHIFT = 4;
    /* Segment field mask. */
    private final static int SEG_MASK = 0x70;

    private static short[] seg_end = {0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};

    private static short search(short val, short[] table, short size) {
        for (short i = 0; i < size; i++) {
            if (val <= table[i]) {
                return i;
            }
        }
        return size;
    }

    /**
     * pcm 转 pcma (两个字节编码成一个字节)
     *
     * @param pcm_val
     * @return pcma
     */
    private 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);
        }
        seg = search(pcm_val, seg_end, (short) 8);
        if (seg >= 8)
            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);
        }
    }

    /**
     * pcma 转 pcm (一个字节解码成2个字节)
     *
     * @param a_val
     * @return pcm
     */
    private static short alaw2linear(byte a_val) {
        a_val ^= 0x55;
        short t = (short) ((a_val & QUANT_MASK) << 4);
        short 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转化成pcma
     * 大小端转化需要使用 ByteUtil的ByteOrder进行配置
     *
     * @param pcm
     * @param pcma
     * @throws IOException
     */
    public static void linear2alaw(File pcm, File pcma) throws IOException {
        FileInputStream inputStream = new FileInputStream(pcm);
        FileOutputStream outputStream = new FileOutputStream(pcma);
        byte[] data = new byte[2];
        int num = inputStream.read(data);
        while (num > 0) {
            short pcm_val = ByteUtil.bytesToShort(data);
            byte a_val = linear2alaw(pcm_val);
            outputStream.write(a_val);
            num = inputStream.read(data);
        }
        inputStream.close();
        outputStream.close();
    }

    /**
     * 将pcm转化成pcma
     * 大小端转化需要使用 ByteUtil的ByteOrder进行配置
     *
     * @param pcma
     * @param pcm
     * @throws IOException
     */
    public static void alaw2linear(File pcma, File pcm) throws IOException {
        FileInputStream inputStream = new FileInputStream(pcma);
        FileOutputStream outputStream = new FileOutputStream(pcm);
        byte[] data = new byte[1];
        int num = inputStream.read(data);
        while (num > 0) {
            byte a_val = data[0];
            short pcm_val = alaw2linear(a_val);
            outputStream.write(ByteUtil.shortToBytes(pcm_val));
            num = inputStream.read(data);
        }
        inputStream.close();
        outputStream.close();
    }

}