Android 实现RTP打包G711,并在VLC播放

1 篇文章 0 订阅
1 篇文章 0 订阅

G711编码有两种,分别是G711A和G711U。本篇文章主要描述Android如何对G711A音频数据RTP打包,并发送到VLC播放器播放出来。

 

Android 音频采集过程我就不说了,下面我贴出对PCM编码成G711A的代码,G711A对PCM的压缩率为50%。

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;   //* sign (7th) bit = 1 二进制的11010101
        } else
        {
            mask = 0x55; //* sign bit = 0  二进制的01010101
            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
        {
            //以下按照表格第一二列进行处理,低4位是数据,5~7位是指数,最高位是符号
            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 转 G711 a率
     *
     * @param pcm
     * @param code
     * @param size
     */
    public static void G711aEncoder(short[] pcm, byte[] code, int size)
    {
        LogUtil.i("PCM数据编码为G.711a");
        for (int i = 0; i < size; i++)
        {
            code[i] = linear2alaw(pcm[i]);
        }
    }

    /**
     * G.711 转 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]);
        }
    }

RTP打包只需要在发送的每一帧数据前面加上12个字节的RTP头即可。

如果设定:

1.采样率为8000

2.单通道

3.位深度为16bit

4.每秒为25帧。

那么每一帧数据的大小为:  8000*16/8/25=640 字节.

RTP时间戳每一帧的增量为:8000/25=320;

所以  RTP时间戳 = 包序号 * 320;

下面贴出设置RTP 头的代码:

    /**
     * @param seqNo 包序号
     * @param timestamp RTP包时间戳
     */
    private void fillInHeader(int seqNo, int timestamp)
    {
        int version = 2;
        int padding = 0;
        int extension = 0;
        int csrc_len = 0;

        int marker = 1;//音频表示会话的开始
        // int payload = 8;
        //short seqNo = 0;

     
        int firstInt = version << 30;
        firstInt = firstInt | (padding << 29);
        firstInt = firstInt | (extension << 28);
        firstInt = firstInt | (csrc_len << 24);

        firstInt = firstInt | (marker << 23);
        firstInt = firstInt | (payload << 16);

  
        firstInt = firstInt | seqNo;

        //timestamp
        // int timestamp = 123456;
        // int ssrc = 13001;

        byte[] temp = intToBytes(firstInt);
        for (int i = 0; i < 4; i++)
        {
            rtpHeader[i] = temp[i];
        }

        temp = intToBytes(timestamp);
        for (int i = 0; i < 4; i++)
        {
            rtpHeader[i + 4] = temp[i];
        }

        temp = intToBytes(ssrc);
        for (int i = 0; i < 4; i++)
        {
            rtpHeader[i + 8] = temp[i];
        }

    }

下面是VLC播放RTP音频流时需要的SDP文件:

m=audio 9870 RTP/AVP 8
a=rtpmap:8 PCMA/8000/2
a=framerate:25
a=control:streamid=0
c=IN IP4 127.0.0.1

m=audio 9870 RTP/AVP 8  中的9870为端口号,8为payload

a=rtpmap:8 PCMA/8000/2  中的8为payload,8000为采样率,2为双通道.

 

完整demo源码下载地址:https://download.csdn.net/download/Navagate/12331100

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值