您的位置:首页 > Web前端 > JavaScript

关于PJSIP 添加视频的思路和想法

2013-11-27 09:55 399 查看
http://hi.baidu.com/tltnoqraczbirzq/item/8a55c79ddb3044b8cc80e51a

 

关于PJSIP 添加视频的思路和想法

pjsip协议栈因为体积小巧效率高,纯C语言开发,被许多SIP客户端使用,包括手机端,PC客户端等。

        csimple android手机端即为pjsip协议栈开发,另外PJSUA为命令行版本的PJSIP。这两个开源项目可以作为PJSIP协议栈开发的参考项目。

        最近我做了个基于PJSIP的PC客户端,http://www.gnetcom.com,因是帮别的公司做的,为一个基础产品,所以并不是太完善,但是基本上使用了PJSIP的功能,另外增加了视频功能,进行了外网测试,NAT穿越等。

        PJSIP增加视频支持,从谷歌搜索到了一篇文章http://blog.csdn.net/lianhuiyong/archive/2009/09/17/4562973.aspx,这里提供了一些基础增加视频的方法,非常值得借鉴。本来考虑直接从这里买来源码,但是后来发现不太适合我的项目,所以最终决定自己开发,这篇文章作者姓廉,是个很不错的人。还发给我了一个参考代码,但是我当时没看懂,随即就删除了,没有用过。

       文章里面提到了修改SDP消息,这个对于SIP增加视频来说是必须的,原来的SDP中只包含音频的各种CODEC,如果增加视频那就要添加H264的支持。SDP修改后,那么视频端口怎么算,这里可以添加一个视频端口,或者直接用音频端口。如果直接用音频端口,那么同时进行视频和音频呼叫就不行了,不过可以换个思路,视频和音频呼叫可以单独进行,分为两个CALL,同样还是一起进行视频语音呼叫的。对于SDP协商成功后RTP传输的问题,个人以为还是用PJSIP原始的RTP打包传输部分比较好,主要原因是如果添加了新的RTP库来进行传输,那么NAT穿越也就是PJNATH部分就不能够很好的整合,也就是说用了新的RTP库,再结合PJNATH进行NAT穿越,重新写接口那就不会很自然。所以尽量在原有代码基础上增加视频的支持,其实是很好的办法。至于用RTPLIB再单独写NAT穿越(STUN/TURN)部分我不太建议。

      解决了传输,NAT穿越,以及SDP修改后,要继续修改H264视频采集编码部分,增加一个H264 编解码器,我从网上下来了FFMPEG和X264进行解码和编码,对于PC客户端应用来说,性能没问题。对于手机端H264解码,要对FFMPEG进行优化,否则解码时候效率非常低。

网上有一个ANDROID FFMPEG优化后的解码器,这个解码器效率很高,就是不稳定,会有内存错误。所以针对ANDROID的FFMPEG解码器还是需要进行优化的。这部分工作完成后,要对CODEC相关位置进行替换,具体办法可以参考音频CODEC 比如 ILBC进行编码和解码的例子。我这里只说思路,不谈代码,因代码其实涉及到的部分非常的多,一两句说不清楚。

     添加视频的主要修改点就是上诉三大块,解决了这三个问题,基本成功一半了,然后就是调试。对于外网穿越,我用了两种类型的路由器进行了测试,路由器类型为Port Restricted Cone NAT 以及
Restricted Cone NAT.  这里先测试了音频,完全没问题可以直接穿越,视频如果你修改的成功的话也是没问题的。对于TURN情况下,其实我个人认为TURN穿越的意义很小。语音穿越也许还有点意义,但是视频几乎没什么意义,测试时用了一个外网的服务器,穿越时视频丢包严重,而且带宽占用率非常高。虽然如此,PJSIP的TURN还是可以用的,单纯从技术上而言。实际意义不大,因为开销太大。视频转发占用的带宽非常多。而且现在98%的路由器都可以用STUN协议穿越,不能穿越的仅限于公司的大型高级NAT,这种情况下如果有一方不是这种NAT。也可以实现穿越。

     对于ANDROID SIP手机客户端的开发,目前来说开源的太多,看懂源码的前提下进行修改时很简单的。比如CSIMPLESIP用的就是PJSIP协议栈,不过个人认为这个项目很乱,不建议参考。

     http://www.gnetcom.com上有我的测试DEMO,包括服务器手机和PC客户端。外网测试通过,有兴趣研究这方面的可以下载后运行下。然后又WIRDSHARK抓包分析下协议。

 

http://blog.csdn.net/lianhuiyong/article/details/4562973

 

关于在pjsip中添加视频的流程说明       

2009-09-17 15:025088人阅读评论(27)收藏举报
videostreamquerythreadsessionsocket

目录(?)[+]

在sdp中添加视频信息
在Invite消息的sdp中添加视频信息
sdp信息中视频的rtp端口的生成

视频处理模块的添加
视频收发以及回放
rtp发送
Rtp接收
远端视频回放
本地视频回放

视频工作线程
发送线程
接收以及回放线程

1.                   在sdp中添加视频信息

添加sdp信息中的视频部分主要通过下面两个步骤处理。

1.1               在Invite消息的sdp中添加视频信息

主要在endpoint.c的pjmedia_endpt_create_sdp()函数中添加。具体的可以看其中的代码,以及代码中的注释。

注意pjmedia_endpt_create_sdp(
pjmedia_endpt *endpt,
                          pj_pool_t *pool,
                          unsigned
stream_cnt,
                          const
pjmedia_sock_info sock_info[2],
                          pjmedia_sdp_session **p_sdp )函数的第三个参数stream_cnt,第四个参数sock_info在使用pjsua_media_channel_create_sdp()调用时,重新调整了输入的参数值。

1.2               sdp信息中视频的rtp端口的生成

在pjus_media.c文件中的pjsua_media_subsys_start()函数使用pjsua_media_transports_create添加创建rtp要使用的transport端口(也就是socket端口)。这样在1中的sdp信息中就可以获取到视频通讯的本地创建的rtp端口。

2.                   视频处理模块的添加

视频处理模块主要完成视频的采集、编码、解码、回放、以及将数据送给rtp或者从rtp获取到数据的功能。其工程为pjmedia-videodev。

CCameraMgr主要实现摄像头的管理功能。如果移植mobile可以考虑修改这部分。

CCodecVideo主要实现视频编解码的功能。如果添加H.263、H.264编解码可以直接修改这部分代码。

CCodecDataChannel主要实现整个视频模块的管理功能。视频的采集、编码、解码、回放、以及将数据送给rtp或者从rtp获取到数据的功能。

Videodev主要实现pjmedia-videodev对Pjsip的外部接口功能。这些接口可以根据需要继续添加。目前应该够用。具体实现见注释。

注意这部分跟rtp交互的接口主要通过两个函数实现。Rtp模块通过pjmedia_video_query_frame_attach接口将回调设置到Pjmedia-videdev模块。Pjmedia-videodev模块,在获取到编码数据后,通过put_frame_video_data将数据送给pjmedia的rtp层,进行rtp打包传输。

3.                   视频收发以及回放

3.1               rtp发送

在stream.c中pjmedia_stream_create_video处理过程中通过调用pjmedia_video_query_frame_attach将回调函数设置给pjmedia-videodev模块。这样,在启动视频工作线程后,就可以通过put_frame_video_data源源不断的将编码后的数据送给stream.c的rtp的put_frame_video接口进行视频的rtp发送。注意这里对于视频包需要拆包处理。

3.2               Rtp接收

对于从rtp接收到的数据。都在stream.c的on_rx_rtp回调来处理。这里处理了视频和音频以及dtmf数据。我们对于解析后pt类型为34(H.263)、31(H.261)的数据直接进行视频处理on_rx_video_rtp。通过on_rx_video_rtp将接收到的视频数据写入pjmedia-videodev的Jitterbuffer(NetPool)中,这样就完成了rtp数据接收视频数据源源不断的输入到pjmedia-videodev模块。

3.3               远端视频回放

对于接收到的视频数据,已经放入netpool中。我们通过启动本地线程不断地从缓冲中获取到数据(视频数据需要重新组赈,然后解码回放),这个通过CCocecDataChnanel:: ShowRemoteVideo来实现。

3.4               本地视频回放

这个简单,也就是直接获取到摄像头的数据,在本地显示的过程。主要通过CCodecDataChannl:: ShowLocalVideo来实现。

4.                   视频工作线程

4.1               发送线程

worker_proc_video主要完成对pjmedia-videdev的pjmedia_video_get_frame_and_send接口的调用。完成视频采集编码并将数据送给rtp的过程。这里注意,对于在pjsip工程中的线程,必须使用pj_thread_create创建,例如:
//add with lianhy in 20090902 创建视频工作线程
    status =
pj_thread_create( endpt->pool,
"video", &worker_proc_video,
        endpt, 0, 0, &endpt->thread_video);

4.2               接收以及回放线程

主要通过Pjmedia-vidodev的接口pjmedia_video_query_frame_start来启动。当然对应的停止应该是pjmedia_video_query_frame_stop。

对于以上说的线程以及socket、session、mediapoint的创建,注意一定要释放(销毁)。

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: