Jrtplib4Android,RTP在Android平台上的使用

由于工作中需要用到rtp协议,java暂时没有比较好的开发框架,参考了其他的一些博文,自己摸索着使用jrtplib库,在此记录一下。

  1. 关于如何编译jrtplib库,在我的上一篇有讲解jrtplib库移植到android上
  2. 可根据自身需求,参考实现的功能。

实现的功能

一、接收端

  1. 接收RTP数据,携带数据并回调通知Java端;
  2. 接收RTCP、BYE等数据,携带数据发送端IP字符串并回调通知Java端;
  3. 实现网络摄像机RTSP协议对接;
  4. 实现接收RTP数据,并转发RTP数据。

二、发送端
1、实现H264编码数据分包发送;
2、发送RTP数据;
3、接收RTCP、BYE等数据,并携带数据发送端IP字符串回调至Java。

准备工作

  • Android.mk 文件编写
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE  := jthread
LOCAL_SRC_FILES := libjthread.a
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE  := jrtp
LOCAL_SRC_FILES := libjrtplib.a
LOCAL_STATIC_LIBRARIES := jthread
include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE    := rtp-handle
LOCAL_SRC_FILES := RtpHandle.cpp RtpReceiver.cpp RtpSender.cpp RtpCommon.cpp
LOCAL_STATIC_LIBRARIES := jthread jrtp
LOCAL_LDLIBS := -llog

include $(BUILD_SHARED_LIBRARY)
  • Application.mk文件编写
#对标准C++ stl库的支持
#APP_STL := stlport_static
APP_STL := gnustl_static
APP_ABI := armeabi-v7a
  • 编写JniHandle操作对象
public class RtpHandle {
    static {
        System.loadLibrary("rtp-handle");
    }

    /**
     * 只发送数据,不做接收处理
     */
    public static native boolean initSendHandle(int localport, String desthost, int destport, RtpListener listener);

    /**
     * 只接收数据,不做发送处理
     */
    public static native boolean initReceiveHandle(String localhost,int localport, RtpListener listener);

    /**
     * 接收数据,并转发
     */
    public static native boolean initReceiveAndSendHandle(String localhost,int localport,String desthost, int destport, RtpListener listener);

    /**
     * 发送数据
     */
    public static native boolean sendH264Byte(byte[] src, int byteLength,boolean isSpsOrPps);

    /**
     * 发送数据
     */
    public static native boolean sendRtpByte(byte[] src, int byteLength,boolean isMarker);

    /**
     * 销毁资源
     */
    public static native boolean finiRtp();

}
  • 接收端实现
BeginDataAccess();
    // check incoming packets
    if (GotoFirstSourceWithData()) {
        do {
            RTPPacket *rtppack = NULL;
            while ((rtppack = GetNextPacket()) != NULL) {
                processRtpPacket(rtppack);
                DeletePacket(rtppack);
            }
        } while (GotoNextSourceWithData());
    }
    EndDataAccess();
if (pack->GetPayloadType() == H264) {
            //std::cout<<"Got H264 packet:êo " << rtppack.GetExtendedSequenceNumber() << " from SSRC " << srcdat.GetSSRC() <GetPayloadData(), pack->GetPayloadLength(), pack->HasMarker(),
                        hid_callback);
        }
  • 发送端实现
//转发rtp数据
void CRTPSender::SendRtpData(unsigned char *m_rtpBuf, int buflen, bool isMarker) {
    if (buflen < 4) {
        return;
    }
    if (mCount % 100 == 0) {
        logd("SendRtpData packet length %d \n", buflen);
        mCount = 0;
    }
    int status;
    this->SetMaximumPacketSize(1500);
    if (isMarker) {
        status = this->SendPacket((void *) m_rtpBuf, buflen, H264, isMarker, 3600);
        CheckError(status);
    } else {
        status = this->SendPacket((void *) m_rtpBuf, buflen, H264, isMarker, 0);
        CheckError(status);
    }
}
void CRTPSender::SendH264Nalu(unsigned char *m_h264Buf, int buflen, bool isSpsOrPps) {
    if (buflen < 4) {
        return;
    }
    unsigned char *pSendbuf; //发送数据指针
    pSendbuf = m_h264Buf;
    //去除前导码0x000001 或者0x00000001
    if (FindStartCode2(m_h264Buf) == 1) {
        pSendbuf = &m_h264Buf[3];
        buflen -= 3;
    } else if (FindStartCode3(m_h264Buf) == 1) {
        pSendbuf = &m_h264Buf[4];
        buflen -= 4;
    }
    char sendbuf[SEND_LENGTH];
    memset(sendbuf, 0, SEND_LENGTH);
    int status;
    if (mCount % 100 == 0) {
        logd("SendH264Nalu packet length %d \n", buflen);
        mCount = 0;
    }
    mCount++;
    if (isSpsOrPps) {
        this->SetDefaultMark(false);
        memcpy(sendbuf, pSendbuf, buflen);
        status = this->SendPacket((void *) sendbuf, buflen);
        CheckError(status);
        return;
    }
    if (buflen <= MAX_RTP_PKT_LENGTH) {
        this->SetDefaultMark(true);
        //设置NALU HEADER,并将这个HEADER填入sendbuf[0]
        nalu_hdr = (NALU_HEADER *) &sendbuf[0]; //将sendbuf[0]的地址赋给nalu_hdr,之后对nalu_hdr的写入就将写入sendbuf中;
        nalu_hdr->F = (char) (pSendbuf[0] & 0x80);
        nalu_hdr->NRI = (char) ((pSendbuf[0] & 0x60)
                >> 5);//有效数据在n->nal_reference_idc的第6,7位,需要右移5位才能将其值赋给nalu_hdr->NRI。
        nalu_hdr->TYPE = (char) (pSendbuf[0] & 0x1f);
        //NALU头已经写到sendbuf[0]中,接下来则存放的是NAL的第一个字节之后的数据。所以从r的第二个字节开始复制
        memcpy(sendbuf + 1, pSendbuf, buflen);
        status = this->SendPacket((void *) sendbuf, buflen);
        CheckError(status);
    } else if (buflen >= MAX_RTP_PKT_LENGTH) {
        this->SetDefaultMark(false);
        //得到该nalu需要用多少长度为1400字节的RTP包来发送
        int k = 0, l = 0;
        k = buflen / MAX_RTP_PKT_LENGTH;//需要k个1400字节的RTP包,这里为什么不加1呢?因为是从0开始计数的。
        l = buflen % MAX_RTP_PKT_LENGTH;//最后一个RTP包的需要装载的字节数
        int t = 0;//用于指示当前发送的是第几个分片RTP包
        while (t < k || (t == k && l > 0)) {
            memset(sendbuf, 0, SEND_LENGTH);
            if (t == 0) {
                //第一片
                //设置FU INDICATOR,并将这个HEADER填入sendbuf[0]
                fu_ind = (FU_INDICATOR *) &sendbuf[0]; //将sendbuf[0]的地址赋给fu_ind,之后对fu_ind的写入就将写入sendbuf中;
                fu_ind->F = (char) (pSendbuf[0] & 0x80);
                fu_ind->NRI = (char) ((pSendbuf[0] & 0x60) >> 5);
                fu_ind->TYPE = 28;  //FU-A类型。
                //设置FU HEADER,并将这个HEADER填入sendbuf[1]
                fu_hdr = (FU_HEADER *) &sendbuf[1];
                fu_hdr->E = 0;
                fu_hdr->R = 0;
                fu_hdr->S = 1;
                fu_hdr->TYPE = (char) (pSendbuf[0] & 0x1f);
                memcpy(sendbuf + 2, &pSendbuf[t * MAX_RTP_PKT_LENGTH + 1], MAX_RTP_PKT_LENGTH);
                status = this->SendPacket((void *) sendbuf, MAX_RTP_PKT_LENGTH + 2, H264, false, 0);
                CheckError(status);
                t++;
            } else if (t < k)//既不是第一片,也不是最后一片
            {
                //设置FU INDICATOR,并将这个HEADER填入sendbuf[0]
                fu_ind = (FU_INDICATOR *) &sendbuf[0]; //将sendbuf[0]的地址赋给fu_ind,之后对fu_ind的写入就将写入sendbuf中;
                fu_ind->F = (char) (pSendbuf[0] & 0x80);
                fu_ind->NRI = (char) ((pSendbuf[0] & 0x60) >> 5);
                fu_ind->TYPE = 28;
                //设置FU HEADER,并将这个HEADER填入sendbuf[1]
                fu_hdr = (FU_HEADER *) &sendbuf[1];
                fu_hdr->R = 0;
                fu_hdr->S = 0;
                fu_hdr->E = 0;
                fu_hdr->TYPE = (char) (pSendbuf[0] & 0x1f);
                memcpy(sendbuf + 2, &pSendbuf[t * MAX_RTP_PKT_LENGTH + 1], MAX_RTP_PKT_LENGTH);
                status = this->SendPacket((void *) sendbuf, MAX_RTP_PKT_LENGTH + 2, H264, false, 0);
                CheckError(status);
                t++;
            }
                //最后一包
            else if (k == t) {
                this->SetDefaultMark(true);
                int iSendLen;
                if (l > 0) {
                    iSendLen = buflen - t * MAX_RTP_PKT_LENGTH;
                } else {
                    iSendLen = MAX_RTP_PKT_LENGTH;
                }
                //设置FU INDICATOR,并将这个HEADER填入sendbuf[0]
                fu_ind = (FU_INDICATOR *) &sendbuf[0]; //将sendbuf[0]的地址赋给fu_ind,之后对fu_ind的写入就将写入sendbuf中;
                fu_ind->F = (char) (pSendbuf[0] & 0x80);
                fu_ind->NRI = (char) ((pSendbuf[0] & 0x60) >> 5);
                fu_ind->TYPE = 28;  //FU-A类型。
                //设置FU HEADER,并将这个HEADER填入sendbuf[1]
                fu_hdr = (FU_HEADER *) &sendbuf[1];
                fu_hdr->R = 0;
                fu_hdr->S = 0;
                fu_hdr->TYPE = (char) (pSendbuf[0] & 0x1f);
                fu_hdr->E = 1;
                memcpy(sendbuf + 2, &pSendbuf[t * MAX_RTP_PKT_LENGTH + 1], iSendLen - 1);
                status = this->SendPacket((void *) sendbuf, iSendLen - 1 + 2, H264, true, 3600);
                CheckError(status);
                t++;
            }
        }
    }
}

具体的代码就不在这里贴出来了,如有需要,可相互学习。
详细代码已上传至GitHub,Jrtplib4Android

你可能感兴趣的:(RTP,jrtplib,rtp,rtp分包,rtp发送h264,android)