HI3518E的ORTP相关代码浅析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33894122/article/details/84973312

前言

之前已经用网盘中的sample_comm_venc.c,编译生成了可以实现功能的代码了,里面添加了一些跟ORTP传输相关的代码,都是用宏的方式添加的,如果想录制保存视频,直接关闭宏就可以。

代码分析

其实过程跟原来还是一样的,采集图像那一套都是不变的,变得就是原来是将三路码流保存到硬盘里,现在是将h.264码流通过网络根据RTP协议发送出去。

在sample_comm_venc.c中添加如下代码

#define ORTP_ENABLE  1

#if ORTP_ENABLE
#include <ortp/ortp.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#define Y_PLOAD_TYPE 96 //H.264
#define MAX_RTP_PKT_LENGTH 1400
#define DefaultTimestampIncrement 3600 //(90000/25)
uint32_t g_userts=0;
RtpSession *pRtpSession = NULL;

#define LOCAL_HOST_IP  "192.168.1.20"

/**  初始化   
*     
*   主要用于对ortp以及其它参数进行初始化   
*   @param:  char * ipStr 目的端IP地址描述串   
*   @param:  int port 目的端RTP监听端口   
*   @return:  RtpSession * 返回指向RtpSession对象的指针,如果为NULL,则初始化失败   
*   @note:      
*/   
RtpSession * rtpInit( char  * ipStr, int  port)
{
RtpSession *session; 
char  *ssrc;
printf("********oRTP for H.264 Init********\n");

ortp_init();
ortp_scheduler_init();
ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR);
session=rtp_session_new(RTP_SESSION_SENDONLY);	

rtp_session_set_scheduling_mode(session,1);
rtp_session_set_blocking_mode(session,0);
//rtp_session_set_connected_mode(session,TRUE);
rtp_session_set_remote_addr(session,ipStr,port);
rtp_session_set_payload_type(session,Y_PLOAD_TYPE);

ssrc=getenv("SSRC");
if (ssrc!=NULL) {
printf("using SSRC=%i.\n",atoi(ssrc));
// 设置输出流的SSRC。不做此步的话将会给个随机值 
rtp_session_set_ssrc(session,atoi(ssrc));
}
return  session;
}
/**  结束ortp的发送,释放资源   
*     
*   @param:  RtpSession *session RTP会话对象的指针   
*   @return:  0表示成功   
*   @note:       
*/    
int  rtpExit(RtpSession *session)   
{ 
printf("********oRTP for H.264 Exit********\n");  
g_userts = 0;   

rtp_session_destroy(session);   
ortp_exit();   
ortp_global_stats_display();   

return  0;   
}   
/**  发送rtp数据包   
*     
*   主要用于发送rtp数据包   
*   @param:  RtpSession *session RTP会话对象的指针   
*   @param:  const char *buffer 要发送的数据的缓冲区地址   
*   @param: int len 要发送的数据长度   
*   @return:  int 实际发送的数据包数目   
*   @note:     如果要发送的数据包长度大于BYTES_PER_COUNT,本函数内部会进行分包处理   
*/   
int  rtpSend(RtpSession *session, char  *buffer,  int  len)
{  
	int  sendBytes = 0; 
	int status;       
	uint32_t valid_len=len-4;
	unsigned char NALU=buffer[4];

	//如果数据小于MAX_RTP_PKT_LENGTH字节,直接发送:单一NAL单元模式
	if(valid_len <= MAX_RTP_PKT_LENGTH)
	{
		sendBytes = rtp_session_send_with_ts(session,
		&buffer[4],
		valid_len,
		g_userts);
	}
	else if (valid_len > MAX_RTP_PKT_LENGTH)
	{
		//切分为很多个包发送,每个包前要对头进行处理,如第一个包
		valid_len -= 1;
		int k=0,l=0;
		k=valid_len/MAX_RTP_PKT_LENGTH;
		l=valid_len%MAX_RTP_PKT_LENGTH;
		int t=0;
		int pos=5;
		if(l!=0)
		{
			k=k+1;
		}
		while(t<k)//||(t==k&&l>0))
		{
			if(t<(k-1))//(t<k&&l!=0)||(t<(k-1))&&(l==0))//(0==t)||(t<k&&0!=l))
			{
				buffer[pos-2]=(NALU & 0x60)|28;
				buffer[pos-1]=(NALU & 0x1f);
				if(0==t)
				{
					buffer[pos-1]|=0x80;
				}
				sendBytes = rtp_session_send_with_ts(session,
				&buffer[pos-2],
				MAX_RTP_PKT_LENGTH+2,
				g_userts);
				t++;
				pos+=MAX_RTP_PKT_LENGTH;
			}
			else //if((k==t&&l>0)||((t==k-1)&&l==0))
			{
				int iSendLen;
				if(l>0)
				{
					iSendLen=valid_len-t*MAX_RTP_PKT_LENGTH;
				}
				else
				iSendLen=MAX_RTP_PKT_LENGTH;
				buffer[pos-2]=(NALU & 0x60)|28;
				buffer[pos-1]=(NALU & 0x1f);
				buffer[pos-1]|=0x40;
				sendBytes = rtp_session_send_with_ts(session,
				&buffer[pos-2],
				iSendLen+2,
				g_userts);
				t++;
			}
		}
	}

	g_userts += DefaultTimestampIncrement;//timestamp increase
	return  len;
}
#endif

上面是ORTP会用到一些函数,rtpInit、rtpExit、rtpSend等,其中rtpInit是在初始化mpp系统的时候一起初始化,rtpSend就是采集完图像之后的发送函数。
在rtpSend发送函数中,有一些操作涉及到h.264的格式,还有一部分跟分包操作相关,因为定义了一次最多发送数据为MAX_RTP_PKT_LENGTH,如果一次需要的数据大于这么多,需要分包操作。

HI_S32 SAMPLE_COMM_VENC_SaveH264(FILE* fpH264File, VENC_STREAM_S *pstStream)
{
    HI_S32 i;

    
    for (i = 0; i < pstStream->u32PackCount; i++)
    {
#if ORTP_ENABLE
		rtpSend(pRtpSession,pstStream->pstPack[i].pu8Addr, pstStream->pstPack[i].u32Len);
#else
        fwrite(pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset,
               pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset, 1, fpH264File);

        fflush(fpH264File);
#endif
    }
    

    return HI_SUCCESS;
}

这是在保存h.264码流的内部,如果开了ORTP_ENABLE宏,就是将h.264码流直接发送出去。

#if ORTP_ENABLE
    /***rtp init****/
    pRtpSession = rtpInit( LOCAL_HOST_IP ,8080);  
    if (pRtpSession==NULL)   
    {   
        printf( "error rtpInit" ); 
        exit(-1);  
        return  0;   
    } 
#endif

这是ORTP库的初始化,和mpp的初始化在一起。
仅仅记录一下操作过程,更详细的ORTP库分析有时间去写一写

VLC客户端sdp文件浅析

m=video 8080 RTP/AVP 96
a=rtpmap:96 H264
a=framerate:15

c=IN IP4 172.18.168.45

  1. m=是媒体级会话的开始处,video:媒体类型 ; 8080:端口号; RTP/AVP:传输协议; 96:rtp头中的payload格式,96是h.264格式的码流

  2. a=rtpmap:证明是动态绑定的进一步说明 ;96:rtp头中的payload格式;H264:编码名 ;缺省了时钟速率,应该为90000,这里的90000是指1s采集90000个字节

  3. a=framerate:25 指1s播放几个rtp包,单位帧每秒,倒数为一个rtp包承载的数据播放的时间,单位s
    90000/25 表示每个时间戳增量值,这个在代码中也是有体现的

  4. c=:媒体链接信息;IN:网络类型一般为IN;IP4:地址类型一般为IP4;后面是IP地址(注意是VLC所在的IP地址,不是发送方的IP)

猜你喜欢

转载自blog.csdn.net/qq_33894122/article/details/84973312