ORTP移植到Hi3518e,h.264封包rtp发送

看到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
这里 129.1.4.196 即为 PC IP Port8080 为监控 rtp 使用端口, payloadtype 96 ,即 h.264.

VLC能够正常播放,但有延时。

 

  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
好的,以下是一个使用alsa库采集音频并使用ortp库打包发送的示例代码,您可以参考: ```c #include <stdio.h> #include <stdlib.h> #include <alsa/asoundlib.h> #include <ortp/ortp.h> // 定义音频参数 #define AUDIO_FORMAT SND_PCM_FORMAT_S16_LE #define AUDIO_CHANNELS 1 #define AUDIO_RATE 44100 #define AUDIO_FRAME_SIZE (AUDIO_CHANNELS * snd_pcm_format_width(AUDIO_FORMAT) / 8) int main(int argc, char *argv[]) { // 初始化ortp库 ortp_init(); // 创建rtp会话 RtpSession *session = rtp_session_new(RTP_SESSION_SENDONLY); if (session == NULL) { fprintf(stderr, "Failed to create rtp session\n"); return -1; } // 设置rtp会话参数 rtp_session_set_scheduling_mode(session, RTP_SCHEDULER_TIME); rtp_session_set_blocking_mode(session, 0); rtp_session_set_payload_type(session, 0); rtp_session_set_tx_timestamp(session, 1); rtp_session_enable_adaptive_jitter_compensation(session, 1); // 解析命令行参数获取目标IP和端口号 if (argc < 3) { fprintf(stderr, "Usage: %s <dest_ip> <dest_port>\n", argv[0]); return -1; } const char *dest_ip = argv[1]; int dest_port = atoi(argv[2]); // 创建rtp传输地址 RtpAddress *addr = rtp_address_new(dest_ip, dest_port, NULL); if (addr == NULL) { fprintf(stderr, "Failed to create rtp address\n"); return -1; } // 打开默认alsa音频设备 snd_pcm_t *handle; if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0) < 0) { fprintf(stderr, "Failed to open audio device\n"); return -1; } // 配置alsa音频设备参数 if (snd_pcm_set_params(handle, AUDIO_FORMAT, SND_PCM_ACCESS_RW_INTERLEAVED, AUDIO_CHANNELS, AUDIO_RATE, 1, 500000) < 0) { fprintf(stderr, "Failed to set audio device parameters\n"); return -1; } // 循环读取音频数据并发送rtp包 char audio_buf[AUDIO_FRAME_SIZE * 1024]; int frame_count = 0; while (1) { // 从alsa设备读取音频数据 int read_count = snd_pcm_readi(handle, audio_buf, 1024); if (read_count < 0) { read_count = snd_pcm_recover(handle, read_count, 0); if (read_count < 0) { fprintf(stderr, "Failed to read audio data\n"); break; } } // 创建rtp包并设置其数据 RtpPacket *packet = rtp_packet_new(AUDIO_FRAME_SIZE * read_count); packet->payloadtype = 0; memcpy(packet->payload, audio_buf, AUDIO_FRAME_SIZE * read_count); packet->timestamp = frame_count * AUDIO_FRAME_SIZE / AUDIO_CHANNELS; packet->marker = 0; // 将rtp发送到目标地址 if (rtp_session_sendto(session, packet->payload, packet->payload_len, addr) < 0) { fprintf(stderr, "Failed to send rtp packet\n"); rtp_packet_free(packet); break; } // 释放rtp包资源 rtp_packet_free(packet); // 增加音频帧计数 frame_count += read_count; } // 关闭alsa设备 snd_pcm_close(handle); // 释放rtp地址和会话资源 rtp_session_destroy(session); rtp_address_destroy(addr); // 清理ortp库资源 ortp_exit(); return 0; } ``` 请注意,此示例代码仅用于演示目的,实际使用时需要根据您的具体需求进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值