Pjsip 视频拉取实现方案

视频拉取,指的是P1拉取P2的摄像头的视频,但是P2是不知道的。

使用Pjsip实现端到端的视频拉取,指的是P1通过拨打视频电话方式和P2通信,但是P2并没有通话的提示,也不用接听动作,P1就可以查看P2摄像头录像的视频,而且只能P1查看P2摄像头的视频和声音,P2是无法查看和听到P1的视频和声音的,说白了就是视频和声音是P2--->P1的单项传输。不过怎么区别普通的视频通话和拉取视频通话呢?这就是下面要说明的。

  • 在sip头加入Pll字段,说明是否是视频拉取
  • 修改sdp中传输方向

1.    Java层


1.1    定义视频拉取通话接口


       在PjsipCall中定义视频拉取接口public boolean makePullVideoCall(String buddyAccount)。
接口实现时,相比普通视频通话需要增加下面的参数定义:
      1)    呼叫参数CallSetting中增加一个Flag定义,参数为64,csetting.setFlag(64);这个flag是c层pjsua_call_make_call函数中pjsua_call_setting参数的flag。
       2)    增加sip协议头中Pll的定义:Pll为Pull的缩写,值为1说明是视频拉取
              sipHeader.setHName("Pll");
              sipHeader.setHValue("1");


1.2    定义音频拉取通话接口


       在PjsipCall中定义视频拉取接口public boolean makePullAudioCall (String buddyAccount)。
接口实现时,相比普通视频通话需要增加下面的参数定义:
       1)    呼叫参数CallSetting中增加一个Flag定义,参数为64,csetting.setFlag(64);这个flag是c层pjsua_call_make_call函数中pjsua_call_setting参数的flag。
        2)    增加sip协议头中Pll的定义:Pll为Pull的缩写,值为1说明是视频拉取
               sipHeader.setHName("Pll");
               sipHeader.setHValue("1");


2.    C层


2.1    pjsua_call结构体中添加isPull定义


        修改位置:pjsip/include/pjsua-lib/pjsua_internal.h
        在struct pjsua_call结构体中新增isPull成员变量,变量类型pj_bool_t类型


2.2    修改pjsua_media_channel_create_sdp函数


         函数位置:pjsip/src/pjsua-lib/pjsua_media.c
         修改函数中pjmedia_endpt_create_audio_sdp和pjmedia_endpt_create_video_sdp这两个函数的调用。把call->opt.flag参数传入,原始调用中,option参数只传0。

2.3    修改pjmedia_endpt_create_audio_sdp


      函数位置:pjmedia/src/pjmedia/endpoint.c
      在文件头中增加static const pj_str_t STR_RECVONLY = { "recvonly", 8 }; //added by dengfei的定义
      把函数中status = init_sdp_media(m, pool, &STR_AUDIO, si);的调用,修改成:status = init_sdp_media_with_flag(m, pool, options, &STR_AUDIO, si);的调用。init_sdp_media_with_flag的实现后面


2.4    修改pjmedia_endpt_create_video_sdp


      函数位置:pjmedia/src/pjmedia/endpoint.c
      在文件头中增加static const pj_str_t STR_RECVONLY = { "recvonly", 8 }; //added by dengfei的定义(前面已经增加,就可以不用再增加了)
      把函数中status = init_sdp_media(m, pool, &STR_AUDIO, si);的调用,修改成:status = init_sdp_media_with_flag(m, pool, options, &STR_AUDIO, si);的调用。init_sdp_media_with_flag的实现后面


2.5    新增函数定义init_sdp_media_with_flag


     函数位置:pjmedia/src/pjmedia/endpoint.c
     函数的实现,基本等同于init_sdp_media,只是在attr->name赋值时,需要根据option的值,判断是否是视频拉取。Option的值,就是java层中CallSetting定义的64的值。
     修改如下:
      if (flg & 64/*PJSUA_CALL_PULL_MEDIA*/) {
        attr->name = STR_RECVONLY;
      } else {
        attr->name = STR_SENDRECV;
      }


2.6    新增函数定义verify_pull_mode_incoming_request


      函数位置:pjsip/src/pjsua-lib/pjsua_call.c
      该函数用于在pjsua_call_on_incoming函数中,判断sip协议头是否携带Pll的定义,和取值,并修改pjsua_call结构体中isPull的取值。


2.7    call.hpp增加pullState值


      在call.hpp的CallInfo中,增加pullState的定义。


2.8    pjsua_call_info增加isPull定义


     修改位置:pjsip/include/pjsua-lib/pjsua.h
在pjsua.h的pjsua_call_info中,增加isPull的定义,代码如下:
      /** is pull vide or audio call */
     pj_bool_t           isPull;


2.9     call.cpp增加pullState的赋值


       在call.cpp的void CallInfo::fromPj(const pjsua_call_info &pci)中,增加pullState           = PJ2BOOL(pci.isPull);赋值,这样java层就的callInfo就可以正常的获取到值。


2.10     pjsua_call_get_info函数中isPull的赋值


      在pjsua_call.c的pjsua_call_get_info函数增加如下代码:
      /*is pull video or audio call*/
      info->isPull = call->isPull;


3.    修改默认视频的分辨率


    1)    修改pjmedia/src/pjmedia-videodev/android_dev.c中的
            #define DEFAULT_WIDTH           640//352
            #define DEFAULT_HEIGHT          480//288
     2)    修改pjmedia/src/pjmedia-codec/openh264.cpp中
            #  define DEFAULT_WIDTH         640//352
            #  define DEFAULT_HEIGHT        480//288
      注意:这个了两个文件要同时修改才能生效


4.    SDP中direction的协商


      代码位置:pjmedia/src/pjmedia/sdp_neg.c
      函数:update_media_direction
      如果remote的direction为recvonly,local的direction就更改为sendonly
 

要在Ubuntu 20.04上使用PJSIP进行视频通话,您需要安装PJSIP库和相关依赖项,并编写一个简单的应用程序来处理视频通话。 以下是一些基本步骤: 1. 安装PJSIP库 您可以使用以下命令从Ubuntu存储库安装PJSIP库: ``` sudo apt-get update sudo apt-get install libpjproject-dev ``` 2. 安装视频编解码器 PJSIP需要视频编解码器才能处理视频。您可以使用以下命令来安装常用的视频编解码器: ``` sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev ``` 3. 编写PJSIP应用程序 您需要编写一个简单的PJSIP应用程序来处理视频通话。以下是一个基本的应用程序示例: ``` #include <pjlib.h> #include <pjmedia.h> #include <pjmedia-videodev.h> int main() { /* 初始化PJSIP库 */ pj_status_t status = pj_init(); /* 创建PJSIP库实例 */ pj_caching_pool cp; pj_pool_t *pool; pjmedia_endpt *med_endpt; pjmedia_vid_dev_index vid_dev_idx; pjmedia_vid_dev_info vid_dev_info; pjmedia_vid_dev_format vid_dev_fmt; pjmedia_vid_dev_cap vid_dev_cap; pjmedia_vid_dev *vid_dev; unsigned i, count; PJ_LOG(3,("pjmedia", "Starting video capture test...")); /* 初始化PJSIP库 */ status = pj_init(); /* 创建PJSIP库实例 */ pj_caching_pool_init(&cp, NULL, 0); pool = pj_pool_create(&cp.factory, "app", 4000, 4000, NULL); /* 创建媒体端点 */ status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt); /* 获取可用的视频设备 */ status = pjmedia_vid_dev_index_enum(&count); for (i=0; i<count; ++i) { if (pjmedia_vid_dev_index_get_info(i, &vid_dev_info) == PJ_SUCCESS) { PJ_LOG(3,("pjmedia", "Video device %d: %s", i, vid_dev_info.name)); } } /* 选择视频设备 */ vid_dev_idx = 0; status = pjmedia_vid_dev_index_get_cap(vid_dev_idx, 0, &vid_dev_cap); status = pjmedia_vid_dev_open(&cp.factory, vid_dev_idx, &vid_dev); /* 设置视频格式 */ pjmedia_vid_dev_format_default(&vid_dev_fmt); vid_dev_fmt.det.vid.size.w = 320; vid_dev_fmt.det.vid.size.h = 240; status = pjmedia_vid_dev_set_format(vid_dev, &vid_dev_fmt); /* 开始视频捕捉 */ status = pjmedia_vid_dev_start(vid_dev); /* 停止视频捕捉 */ status = pjmedia_vid_dev_stop(vid_dev); /* 销毁视频设备 */ pjmedia_vid_dev_close(vid_dev); /* 销毁媒体端点 */ pjmedia_endpt_destroy(med_endpt); /* 销毁PJSIP库实例 */ pj_pool_release(pool); pj_caching_pool_destroy(&cp); pj_shutdown(); return 0; } ``` 上面的代码演示了如何使用PJSIP捕获视频。您需要编写更多的代码来处理视频流并进行视频通话。 4. 编译和运行应用程序 编译应用程序的命令如下: ``` gcc -o video_call video_call.c -lpjproject -lpjmedia -lpjmedia-videodev -lswscale -lavcodec -lavformat -lswresample ``` 运行应用程序的命令如下: ``` ./video_call ``` 以上是基本步骤,当然还需要根据您的具体需求进行更多的设置和编码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值