java 封裝rtp流


下面是RTP實現FU-A分包方式的代碼,其中每個包的大小是1400字節。注釋比較全面,看代碼就行

    private void sendData(byte[] r, int h264len)throws IOException {
        memset(sendbuf, 0, 1500);
        sendbuf[1] = (byte) (sendbuf[1] | 96); // 負載類型號96,其值為:01100000
        sendbuf[0] = (byte) (sendbuf[0] | 0x80); // 版本號,此版本固定為2
        sendbuf[1] = (byte) (sendbuf[1] & 254); //標志位,由具體協議規定其值,其值為:01100000
        sendbuf[11] = 10;//隨機指定10,並在本RTP回話中全局唯一,java默認采用網絡字節序號 不用轉換(同源標識符的最后一個字節)
        if (h264len <= packageSize) {
            sendbuf[1] = (byte) (sendbuf[1] | 0x80); // 設置rtp M位為1,其值為:11100000,分包的最后一片,M位(第一位)為0,后7位是十進制的96,表示負載類型
            System.arraycopy(intToByte(seq_num++), 0, sendbuf, 2, 2);//send[2]和send[3]為序列號,共兩位
            {
                // java默認的網絡字節序是大端字節序(無論在什么平台上),因為windows為小字節序,所以必須倒序
                /**參考:
                 * http://blog.csdn.net/u011068702/article/details/51857557
                 * http://cpjsjxy.iteye.com/blog/1591261
                 */
                byte temp = 0;
                temp = sendbuf[3];
                sendbuf[3] = sendbuf[2];
                sendbuf[2] = temp;
            }
            // FU-A HEADER, 並將這個HEADER填入sendbuf[12]
            sendbuf[12] = (byte) (sendbuf[12] | ((byte) (r[0] & 0x80)) << 7);
            sendbuf[12] = (byte) (sendbuf[12] | ((byte) ((r[0] & 0x60) >> 5)) << 5);
            sendbuf[12] = (byte) (sendbuf[12] | ((byte) (r[0] & 0x1f)));
            // 同理將sendbuf[13]賦給nalu_payload
            //NALU頭已經寫到sendbuf[12]中,接下來則存放的是NAL的第一個字節之后的數據。所以從r的第二個字節開始復制
            System.arraycopy(r, 1, sendbuf, 13, h264len - 1);
            ts_current = ts_current + timestamp_increse;
            System.arraycopy(intToByte(ts_current), 0, sendbuf, 4, 4);//序列號接下來是時間戳,4個字節,存儲后也需要倒序
            {
                byte temp = 0;
                temp = sendbuf[4];
                sendbuf[4] = sendbuf[7];
                sendbuf[7] = temp;
                temp = sendbuf[5];
                sendbuf[5] = sendbuf[6];
                sendbuf[6] = temp;
            }
            bytes = h264len + 12;//獲sendbuf的長度,為nalu的長度(包含nalu頭但取出起始前綴,加上rtp_header固定長度12個字節)
             client.send(new DatagramPacket(sendbuf, bytes, addr, port/*9200*/));
            //send(sendbuf,bytes);

        } else if (h264len > packageSize) {
            int k = 0, l = 0;
            k = h264len / packageSize;
            l = h264len % packageSize;
            int t = 0;
            ts_current = ts_current + timestamp_increse;
            System.arraycopy(intToByte(ts_current), 0, sendbuf, 4, 4);//時間戳,並且倒序
            {
                byte temp = 0;
                temp = sendbuf[4];
                sendbuf[4] = sendbuf[7];
                sendbuf[7] = temp;
                temp = sendbuf[5];
                sendbuf[5] = sendbuf[6];
                sendbuf[6] = temp;
            }
            while (t <= k) {
                System.arraycopy(intToByte(seq_num++), 0, sendbuf, 2, 2);//序列號,並且倒序
                {
                    byte temp = 0;
                    temp = sendbuf[3];
                    sendbuf[3] = sendbuf[2];
                    sendbuf[2] = temp;
                }
                if (t == 0) {//分包的第一片
                    sendbuf[1] = (byte) (sendbuf[1] & 0x7F);//其值為:01100000,不是最后一片,M位(第一位)設為0
                    //FU indicator,一個字節,緊接在RTP header之后,包括F,NRI,header
                    sendbuf[12] = (byte) (sendbuf[12] | ((byte) (r[0] & 0x80)) << 7);//禁止位,為0
                    sendbuf[12] = (byte) (sendbuf[12] | ((byte) ((r[0] & 0x60) >> 5)) << 5);//NRI,表示包的重要性
                    sendbuf[12] = (byte) (sendbuf[12] | (byte) (28));//TYPE,表示此FU-A包為什么類型,一般此處為28
                    //FU header,一個字節,S,E,R,TYPE
                    sendbuf[13] = (byte) (sendbuf[13] & 0xBF);//E=0,表示是否為最后一個包,是則為1
                    sendbuf[13] = (byte) (sendbuf[13] & 0xDF);//R=0,保留位,必須設置為0
                    sendbuf[13] = (byte) (sendbuf[13] | 0x80);//S=1,表示是否為第一個包,是則為1
                    sendbuf[13] = (byte) (sendbuf[13] | ((byte) (r[0] & 0x1f)));//TYPE,即NALU頭對應的TYPE
                    //將除去NALU頭剩下的NALU數據寫入sendbuf的第14個字節之后。前14個字節包括:12字節的RTP Header,FU indicator,FU header
                    System.arraycopy(r, 1, sendbuf, 14, packageSize);
                     client.send(new DatagramPacket(sendbuf, packageSize+14, addr, port/*9200*/));
                    t++;
                } else if (t == k) {//分片的最后一片
                    sendbuf[1] = (byte) (sendbuf[1] | 0x80);

                    sendbuf[12] = (byte) (sendbuf[12] | ((byte) (r[0] & 0x80)) << 7);
                    sendbuf[12] = (byte) (sendbuf[12] | ((byte) ((r[0] & 0x60) >> 5)) << 5);
                    sendbuf[12] = (byte) (sendbuf[12] | (byte) (28));

                    sendbuf[13] = (byte) (sendbuf[13] & 0xDF); //R=0,保留位必須設為0
                    sendbuf[13] = (byte) (sendbuf[13] & 0x7F); //S=0,不是第一個包
                    sendbuf[13] = (byte) (sendbuf[13] | 0x40); //E=1,是最后一個包
                    sendbuf[13] = (byte) (sendbuf[13] | ((byte) (r[0] & 0x1f)));//NALU頭對應的type

                    if (0 != l) {//如果不能整除,則有剩下的包,執行此代碼。如果包大小恰好是1400的倍數,不執行此代碼。
                        System.arraycopy(r, t * packageSize + 1, sendbuf, 14, l - 1);//l-1,不包含NALU頭
                        bytes = l - 1 + 14; //bytes=l-1+14;
                        client.send(new DatagramPacket(sendbuf, bytes, addr, port/*9200*/));
                        //send(sendbuf,bytes);
                    }//pl
                    t++;
                } else if (t < k && 0 != t) {//既不是第一片,又不是最后一片的包
                    sendbuf[1] = (byte) (sendbuf[1] & 0x7F); //M=0,其值為:01100000,不是最后一片,M位(第一位)設為0.
                    sendbuf[12] = (byte) (sendbuf[12] | ((byte) (r[0] & 0x80)) << 7);
                    sendbuf[12] = (byte) (sendbuf[12] | ((byte) ((r[0] & 0x60) >> 5)) << 5);
                    sendbuf[12] = (byte) (sendbuf[12] | (byte) (28));

                    sendbuf[13] = (byte) (sendbuf[13] & 0xDF); //R=0,保留位必須設為0
                    sendbuf[13] = (byte) (sendbuf[13] & 0x7F); //S=0,不是第一個包
                    sendbuf[13] = (byte) (sendbuf[13] & 0xBF); //E=0,不是最后一個包
                    sendbuf[13] = (byte) (sendbuf[13] | ((byte) (r[0] & 0x1f)));//NALU頭對應的type
                    System.arraycopy(r, t * packageSize + 1, sendbuf, 14, packageSize);//不包含NALU頭
                     client.send(new DatagramPacket(sendbuf, packageSize+14, addr, port/*9200*/));
                    //send(sendbuf,1414);
                    t++;
                }
            }
        }
    }

其他的參數和代碼:

  private byte[] sendbuf=new byte[1500];
  private int packageSize=1400;
  private  int seq_num = 0;
  private timestamp_increse=(int)(90000.0/framerate);//framerate是幀率
  private int ts_current=0;
  private  int  bytes=0;


// 清空buf的值
    public void memset(byte[] buf, int value, int size) {
        for (int i = 0; i < size; i++) {
            buf[i] = (byte) value;
        }
    }


//返回的是4個字節的數組。
public byte[] intToByte(int number) {
    int temp = number;
    byte[] b = new byte[4];
    for (int i = 0; i < b.length; i++) {
        b[i] = new Integer(temp & 0xff).byteValue();
        temp = temp >> 8;
    }
    return b;
}

  h264每個NAL單元去掉起始符之后,直接將NAL單元數據作為sendData()的參數,就可以直接發送了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM