ORTP的介绍
- openRTP,用C实现的一个RTP库(其实还有C++实现的,JAVA等实现的)
- 实质是一个视频服务器,工作时客户端和服务器实时传递视频数据
- 一般认为RTP工作在传输层,但是其实RTP比TCP/UDP高一个层次
- RTP(及RTCP)的实现有国际标准RFC3550规定,只要符合协议谁都可以自己写一个
- 本季课程重点在于使用ORTP来实现局域网视频实时传输
ORTP库的移植
- 准备源码
- 下载ortp源码:https://github.com/dmonakhov/ortp
- 存放到临时工作目录并解压
- 源码修改
- 增加H.264的payload支持。
在src/avprofile.c中357行添加:
rtp_profile_set_payload(profile,96,&payload_type_h264);
- 配置和编译、安装
- 进入ortp目录执行./autogen.sh
- 错误1:./autogen.sh: line 44: libtoolize: command not found
解决:sudo apt-get install libtool* - 错误2:libtoolize: error: Please install GNU M4, or ‘export M4=/path/to/gnu/m4’.
解决:sudo apt-get install m4 - 错误3:Automake - aclocal: command not found
解决:sudo apt-get install automake - 继续执行./configure --prefix=/tmp/ortp --host=arm-himix100-linux
- /tmp/ortp是安装目录
- arm-himix100-linux:指定编译器,3516用的arm-himix100-linux-gcc 朱友鹏老师的3518E用的是arm-hisiv300-linux要注意替换。
- make && make install
- 到/tmp/ortp目录下查看移植好的库和头文件
RTP传输视频实战
- 在官方SDK的sample中添加rtp传输代码
- 在sample_comm_venc.c中的SAMPLE_COMM_VENC_MemConfig()函数之前添加如下代码
#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.100"/** 初始化 * * 主要用于对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;}elseiSendLen=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 increasereturn len;
}#endif
- 修改sample_venc.c中的
VideoChn[2] = {0,2}; -> VideoChn[2] = {2,0};
表示会先传输视频通道2,因为视频通道2是H.64协议的通道
- 修改sample_venc.c中
SAMPLE_COMM_VENC_StartGetStream(VideoChn, 2);
->
SAMPLE_COMM_VENC_StartGetStream(VideoChn, 1);
表示只传输一个通道那就是H.264
- 在sample_comm_venc.c中SAMPLE_COMM_VENC_GetVencStreamProc()添加
#if ORTP_ENABLE/***rtp init****/pRtpSession = rtpInit( LOCAL_HOST_IP ,8080); if (pRtpSession==NULL) { printf( "error rtpInit" ); exit(-1); return 0; } #endif
step 2: Start to get streams of each channel.前面添加初始化ORTP的代码
- LOCAL_HOST_IP :表示数据流推送的目的IP
- 8080:我们打开电脑监视的IP
- SAMPLE_COMM_VENC_SaveStream()中添加
#if ORTP_ENABLErtpSend(pRtpSession,pstStream->pstPack[i].pu8Addr, pstStream->pstPack[i].u32Len);#elsefwrite(pstStream->pstPack[i].pu8Addr+pstStream->pstPack[i].u32Offset,pstStream->pstPack[i].u32Len-pstStream->pstPack[i].u32Offset, 1, fpH264File);fflush(fpH264File);#endif
如果 开启了ORTP传输就把数据推送出去,而不写在本地文件夹
- 复制 /tmp/otrp/文件夹到 mpp/include/文件夹下
- 修改 up_linux.mak编译文件
从:
$(TARGET):$(COMM_OBJ) $(OBJS)@$(CC) $(CFLAGS) -lpthread -lm -o $(TARGET_PATH)/$@ $^ -Wl,--start-group $(MPI_LIBS) $(SENSOR_LIBS) $(AUDIO_LIBA) $(REL_LIB)/libsecurec.a -Wl,--end-group$(waring $(cc))
至
$(TARGET):$(COMM_OBJ) $(OBJS)@$(CC) $(CFLAGS) -lpthread -lm -lortp -o $(TARGET_PATH)/$@ $^ -L/tmp/ortp/lib -Wl,--start-group $(MPI_LIBS) $(SENSOR_LIBS) $(AUDIO_LIBA) $(REL_LIB)/libsecurec.a -Wl,--end-group$(waring $(cc))
添加了ORTP的so文件。让编译器找libortp.so文件
-
执行make.生成sample_venc
-
复制/tmp/ortp/lib 目下下的libortp.so,libortp.so.9,libortp.so.9.0.0到开发板的/usr/lib目录下
-
复制刚刚生成的 sample_venc文件到开发板执行
-
在windows端写一个VLC配置文件命名为demo.sdp
m=video 8080 RTP/AVP 96
a=rtpmap:96 H264
a=framerate:25
c=IN IP4 192.168.1.100
*用VLC打开demo.sdp 就可以看到开发板传递过来的图像了