linux使用jrtplib收发h264数据

本文介绍了如何使用jrtplib库简化RTP协议参数配置,实现H.264视频的实时发送和接收。重点讲解了如何处理超过MUT大小的数据帧,确保数据包正确组装和解码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        之前介绍过自己直接使用RTP收发h.264数据,这样有一个麻烦就是RTP协议的各个参数需要自己一个一个位的去填充,这样不利于发送也不方便接收。jrtplib库就刚好解决了这样的麻烦,同时它还提供了很多RTCP的信息查询接口,这样为实现实时流控制提供了方便。

    在本文中,将介绍h264 通过jrtplib库来实现实时的发送和接收。发送方发送,按照编码的习惯,我们习惯上是每完成一帧数据的编码就整一帧数据的发送。与此类似,在接收端,我们也是喜欢将整一帧的数据接收完整后再进行解码等处理。但是,这样会带来一个问题,我们网络最大传输单位MUT 一般是1400个字节,而我们进行h.264数据编码的时候,很多数据帧会大于1400帧,所以需要分开几个数据包来发送,在接收的时候,需要将分开的数据包再合成一个数据帧。

注明:

    下面代码是在我电脑写的最简程序。

    发送端IP:192.168.0.5

    接收端IP:192.168.0.6

    发送端口:6666

    接收端口:6664

注意几点:

    (1)jrtplib不能使用基数端口,基数端口用来建立RTCP

    (2)jrtplib设置的默认MUT是1400,但是实际每包数据不能发送1400字节,因为它还有TCP 头数据

receive.c

/*=============================================================================  
 *     FileName: receive.cpp  
 *         Desc: reveive h.264 from RTP server 
 *       Author: licaibiao  
 *   LastChange: 2017-04-22  
 * =============================================================================*/
#include <jrtplib3/rtpsession.h>
#include <jrtplib3/rtpudpv4transmitter.h>
#include <jrtplib3/rtpipv4address.h>
#include <jrtplib3/rtpsessionparams.h>
#include <jrtplib3/rtperrors.h>
#include <jrtplib3/rtplibraryversion.h>
#include <jrtplib3/rtppacket.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
 
using namespace jrtplib;
 
void checkerror(int rtperr)
{
    if (rtperr < 0)
    {
        std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
        exit(-1);
    }
}
 
int main(void)
{    
    RTPSession sess;
    uint16_t portbase = 6664;
    int status;
    bool done = false;
 
    RTPUDPv4TransmissionParams transparams;
    RTPSessionParams sessparams;
    sessparams.SetOwnTimestampUnit(1.0/10.0);        
    
    sessparams.SetAcceptOwnPackets(true);
 
    transparams.SetPortbase(portbase);
    status = sess.Create(sessparams,&transparams);    
    checkerror(status);
 
    sess.BeginDataAccess();
    RTPTime delay(0.001);
    RTPTime starttime = RTPTime::CurrentTime();
    
    FILE *fd;
    size_t len;
    uint8_t *loaddata;
    RTPPacket *pack;
    uint8_t buff[1024*100] = {0};
    int pos = 0;
    
    fd = fopen("./test_recv.h264","wb+");
    while (!done)
    {
        status = sess.Poll();
        checkerror(status);
            
        if (sess.GotoFirstSourceWithData())
        {
            do
            {
                while ((pack = sess.GetNextPacket()) != NULL)
                {
                    
                    loaddata = pack->GetPayloadData();
                    len         = pack->GetPayloadLength();
                    
                    if(pack->GetPayloadType() == 96) //H264
                    {
                        if(pack->HasMarker()) // the last packet
                        {
                            memcpy(&buff[pos],loaddata,len);    
                            fwrite(buff, 1, pos+len, fd);
                            pos = 0;
                        }
                        else
                        {
                            memcpy(&buff[pos],loaddata,len);
                            pos = pos + len;    
                        }
                    }else
                    {
                        printf("!!!  GetPayloadType = %d !!!! \n ",pack->GetPayloadType());
                    }
 
                    sess.DeletePacket(pack);
                }
            } while (sess.GotoNextSourceWithData());
        }
                
        RTPTime::Wait(delay);
        RTPTime t = RTPTime::CurrentTime();
        t -= starttime;
        if (t > RTPTime(40.0))
            done = true;
    }
    fclose(fd);
    
    sess.EndDataAccess();
    delay = RTPTime(10.0);
    sess.BYEDestroy(delay,0,0);
    
    return 0;
}


 发送端程序 sender

/*=============================================================================  
 *     FileName: sender.cpp  
 *         Desc: sending h.264 data to client    
 *       Author: licaibiao  
 *   LastChange: 2017-04-22  
 * =============================================================================*/
#include <jrtplib3/rtpsession.h>
#include <jrtplib3/rtpudpv4transmitter.h>
#include <jrtplib3/rtpipv4address.h>
#include <jrtplib3/rtpsessionparams.h>
#include <jrtplib3/rtperrors.h>
#include <jrtplib3/rtplibraryversion.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
 
using namespace jrtplib;
 
#define MAXLEN    (RTP_DEFAULTPACKETSIZE - 100)
 
void checkerror(int rtperr){
    if (rtperr < 0){
        std::cout << "ERROR: " << RTPGetErrorString(rtperr) << std::endl;
        exit(-1);
    }
}
 
class MyRTPSession : public RTPSession{
    public:  
        MyRTPSession(void);  
        ~MyRTPSession(void); 
        void SendH264Nalu(RTPSession* sess,uint8_t* m_h264Buf,int buflen);   
    protected:  
        
 
};
 
MyRTPSession::MyRTPSession(void){}  
MyRTPSession::~MyRTPSession(void){}
 
int main(void)
{    
    int i;
    int num;
    int status;
    
    RTPSession sess;
    MyRTPSession sender;
    uint16_t portbase = 6666;  
    uint16_t destport = 6664;
    uint8_t destip[]={192,168,0,6};
 
    RTPUDPv4TransmissionParams transparams;
    RTPSessionParams sessparams;
 
    /* set h264 param */
    sessparams.SetUsePredefinedSSRC(true);  //设置使用预先定义的SSRC    
    sessparams.SetOwnTimestampUnit(1.0/9000.0); /* 设置采样间隔 */
    sessparams.SetAcceptOwnPackets(true);   //接收自己发送的数据包  
    
    transparams.SetPortbase(portbase);
    status = sess.Create(sessparams,&transparams);    
    checkerror(status);
    
    RTPIPv4Address addr(destip,destport);
    status = sess.AddDestination(addr);
    checkerror(status);
 
    sess.SetDefaultTimestampIncrement(3600);/* 设置时间戳增加间隔 */
    sess.SetDefaultPayloadType(96);
    sess.SetDefaultMark(true);    
 
    FILE *fd;
    int pos = 0;
    int header_flag = 0; 
    uint8_t buff[1024*100] = {0};
 
    fd = fopen("./test.h264","rb");
    fread(buff, 1, 4, fd);
    if((buff[0]==0)&&(buff[1]==0)&&(buff[2]==0)&&(buff[3]==1)){
        header_flag = 1;
        pos = 4;
    }else{
        header_flag = 0;
        pos = 3;
    }
    
    while((feof(fd)==0))
    {
        buff[pos++] = fgetc(fd);
        
        if(header_flag == 1){  //00 00 00 01
            if((buff[pos-1]==1)&&(buff[pos-2]==0)&&(buff[pos-3]==0)&&(buff[pos-4]==0)){
                   sender.SendH264Nalu(&sess, buff,pos-4);
                buff[0] = 0x00;
                buff[1] = 0x00;
                buff[2] = 0x00;
                buff[3] = 0x01;
                pos = 4;
 
                RTPTime::Wait(0.03);
             }
            
        }
        else{   
            if((buff[pos-1]==1)&&(buff[pos-2]==0)&&(buff[pos-3]==0)){
                   sender.SendH264Nalu(&sess, buff, pos-3);
                   buff[0] = 0x00;
                   buff[1] = 0x00;
                   buff[3] = 0x01;
                   pos = 3;
 
                RTPTime::Wait(0.03);
            }
         
        }
    }
    if(pos != 0){
        sender.SendH264Nalu(&sess,buff,pos);
    }
    fclose(fd);
    printf("end of the read\n");
    sess.BYEDestroy(RTPTime(10,0),0,0);    
    return 0;
}


 

在上面的代码中,去掉了void SendH264Nalu(RTPSession* sess,uint8_t* m_h264Buf,int buflen) 函数的实现

原文链接:https://blog.youkuaiyun.com/li_wen01/article/details/70435005

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值