liusuyi
6 天以前 307977cfb9fb88f845e36e4041c082ffdd691da5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package cn.org.hentai.jtt1078.codec;
 
import cn.org.hentai.jtt1078.codec.AudioCodec;
 
/**
 * 核心转换,PCM转G711
 * Created by onlygx
 */
public class G711Codec extends AudioCodec
{
    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};
    private final static int cClip = 32635;
    private static final byte[] aLawCompressTable = new byte[]{1, 1, 2, 2, 3, 3, 3,
            3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
            5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
            6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7,
            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
 
    private static byte linearToALawSample(short sample) {
        int sign;
        int exponent;
        int mantissa;
        int s;
 
        sign = ((~sample) >> 8) & 0x80;
        if (!(sign == 0x80)) {
            sample = (short) -sample;
        }
        if (sample > cClip) {
            sample = cClip;
        }
        if (sample >= 256) {
            exponent = aLawCompressTable[(sample >> 8) & 0x7F];
            mantissa = (sample >> (exponent + 3)) & 0x0F;
            s = (exponent << 4) | mantissa;
        } else {
            s = sample >> 4;
        }
        s ^= (sign ^ 0x55);
        return (byte) s;
    }
 
    /**
     * PCM转G711
     *
     * @param src 编码前的数据
     * @return 编码后res数组长度应为编码前src数组长度的一半
     */
    public static byte[] encode(byte[] src) {
        int j = 0;
        int len = src.length;
        int count = len / 2;
        byte[] res = new byte[count];
        short sample = 0;
        for (int i = 0; i < count; i++) {
            sample = (short) (((src[j++] & 0xff) | (src[j++]) << 8));
            res[i] = linearToALawSample(sample);
        }
        return res;
    }
 
    static short search(short val, short[] table, short size) {
 
        for (short i = 0; i < size; i++) {
            if (val <= table[i]) {
                return i;
            }
        }
        return size;
    }
 
    public 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);
        }
 
        /* 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);
        }
    }
 
 
    public 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;
    }
 
    // 由G.711转至PCM
    public static byte[] _toPCM(byte[] g711data) {
        byte[] pcmdata = new byte[g711data.length * 2];
        for (int i = 0, k = 0; i < g711data.length; i++) {
            short v = alaw2linear(g711data[i]);
            pcmdata[k++] = (byte) (v & 0xff);
            pcmdata[k++] = (byte) ((v >> 8) & 0xff);
        }
        return pcmdata;
    }
 
    // 由PCM转至G.711
    public static byte[] _fromPCM(byte[] pcmData) {
        return encode(pcmData);
    }
 
    @Override
    public byte[] toPCM(byte[] data) {
        byte[] temp;
        // 如果前四字节是00 01 52 00,则是海思头,需要去掉
        if (data[0] == 0x00 && data[1] == 0x01 && (data[2] & 0xff) == (data.length - 4) / 2 && data[3] == 0x00) {
            temp = new byte[data.length - 4];
            System.arraycopy(data, 4, temp, 0, temp.length);
        } else temp = data;
 
        return _toPCM(temp);
    }
 
    @Override
    public byte[] fromPCM(byte[] data) {
        return encode(data);
    }
}