【转载】原文地址:http://blog.csdn.net/jiaozi07/article/details/41749943
注:评论请移步至原文。
看到ORTP是纯C实现的rtp库,于是移植到3518e试用一下.
1.下载源码
http://www.linphone.org/technical-corner/ortp/downloads
里面有个tar res跳转链接跳转入
http://download.savannah.gnu.org/releases/linphone/ortp/sources/
下载最新的ortp-0.23.0.tar.gz,并解压
2.编译
之前露写了h.264类型的添加,即需先修改src/avprofile.c文件中av_profile_init函数,在最后添加上:
rtp_profile_set_payload(profile,96,&payload_type_h264);
这里的96也就是为h.264指定的负载类型,也就是后面rtp_session_set_payload_type需要设置的类型,以及VLC配置文件中的类型,这样就支持了H.264协议.然后在配置编译如下:
./configure --prefix=/work/hi3518/ortp --host=arm-hisiv100nptl-linux
make
make install
配置只需指定安装目录prefix,编译平台host即可,这里host直接赋值arm-hisiv100nptl-linux-gcc前缀即可,注意不是arm-hisiv100nptl-linux-而是arm-hisiv100nptl-linux。
3.部署到开发板
将编译生成的库/work/hi3518/ortp/lib/libortp.so.9复制到开发板/usr/lib中
4.添加ortp库到mpp2中
在海思SDK mpp2目录下新建rtp目录,将/work/hi3518/ortp/下全部内容复制到该目录下,
修改mpp2/sample/Makefile.param,添加:
INC_FLAGS += -I$(MPP_PATH)/rtp/include -L$(MPP_PATH)/rtp/lib/ -lortp
5.修改代码
示例程序venc中有将视频进行264编码并保存为文件(nfs挂载),这里一步步分析sample_venc.c即可找到最终的保存是通过sample_comm_venc.c中的SAMPLE_COMM_VENC_SaveH264函数完成的,这里只要修改该函数为封包发送即可。
下面是sample_comm_venc.c中需要添加的部分:
- #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;
- /** 初始化
- *
- * 主要用于对ortp以及其它参数进行初始化
- * @param: char * ipStr 目的端IP地址描述串
- * @param: iint 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];
- //printf("send len=%d\n",len);
- //如果数据小于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);
- return sendBytes;
- }
- 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;
- }
在实现调用前需要进行ortp加载初始化,我们在该文件中的函数SAMPLE_COMM_VENC_GetVencStreamProc中添加初始化即可:
- /***rtp init****/
- pRtpSession = rtpInit( "129.1.4.196" ,8080);
- if (pRtpSession==NULL)
- {
- printf( "error rtpInit" );
- exit(-1);
- return 0;
- }
- /******************************************
- step 2: Start to get streams of each channel.
- ******************************************/
注:这里为了简便在程序中写死了发送目标为129.1.4.196:8080,这要与下面的cfg.sdp对应.
然后修改SAMPLE_COMM_VENC_SaveH264函数调用rtp发送:
- /*****************************************************************************
- * funciton : save H264 stream
- ******************************************************************************/
- HI_S32 SAMPLE_COMM_VENC_SaveH264(FILE* fpH264File, VENC_STREAM_S *pstStream)
- {
- HI_S32 i;
- for (i = 0; i < pstStream->u32PackCount; i++)
- {
- #if 0
- fwrite(pstStream->pstPack[i].pu8Addr[0],
- pstStream->pstPack[i].u32Len[0], 1, fpH264File);
- fflush(fpH264File);
- if (pstStream->pstPack[i].u32Len[1] > 0)
- {
- fwrite(pstStream->pstPack[i].pu8Addr[1],
- pstStream->pstPack[i].u32Len[1], 1, fpH264File);
- fflush(fpH264File);
- }
- #else
- rtpSend(pRtpSession,
- pstStream->pstPack[i].pu8Addr[0],
- pstStream->pstPack[i].u32Len[0]);
- if (pstStream->pstPack[i].u32Len[1] > 0)
- {
- rtpSend(pRtpSession,
- pstStream->pstPack[i].pu8Addr[1],
- pstStream->pstPack[i].u32Len[1]);
- }
- #endif
- }
- return HI_SUCCESS;
- }
这样编译获得 sample_venc.
6.运行
将sample_venc加载到开发板并运行,
#./sample_venc 0
please press twice ENTER to exit this sample
********oRTP for H.264 Init********
Av profile add H.264
ortp-message-Setting random local addresses.
ortp-message-rtp session [0x1c95758] set to rtp [129.1.4.196:8080] rtcp [129.1.4.196:8081]
ortp-message-Using permissive algorithm
ortp-message-Sending RTCP SR compound message on session [0x1c95758].
ortp-message-Sending RTCP SR compound message on session [0x1c95758].
......
7.VLC播放
PC端使用VLC来播放,编写cfg.sdp如下:
- m=video 8080 RTP/AVP 96
- a=rtpmap:96 H264/90000;
- a=decode_buf=300;
- a=framerate:25
- c=IN IP4 129.1.4.196
VLC能够正常播放,但有延时。