天天看點

使用pjsip傳輸已經編碼的視訊,源碼在github

pjsip功能很強,做sip rtp語音通話庫首選。在2.0之後,也支援視訊。不過,它的視訊功能預設是從視訊裝置采集,然後進行編譯,再發送出去的。假設,我們已經有了視訊源,比如IP錄影機,不需要采集和編碼這個過程,怎麼處理呢?假設我們采用pjsip附帶的pjsua為例。

通常的方法:

1 把視訊源當然檔案來處理,sample有。不過這種方法用的不多。

2 修改vid_stream.c,在put_frame和get_frame裡,換上我們自己的視訊源。這種方法使用的最多,很多人在1.x版本裡支援視訊,就用這種方法。

3 本文采用的:重新構造sdp,自己建立rtp通道。

前兩個方法思路直接,代碼量都不小,尤其是第二種,需要修改pj底層代碼。

如果基于pjsua做一個簡單的視訊通信,可以采用本文中的方法。其實代碼量也不小,不過sample提供了參考,實作起來也比較容易。下面簡單說明:

1 關鍵點在sdp上,pjsua_call_make_call這個函數非常友善,直接呼叫對方。不過它在底層做了太多工作,比如啟動了聲霸卡。而不用這個函數,直接用比較底層的pjsip_inv_send_msg,自己處理的工作相對比較多(但不難,不過這樣就不需要pjsua這個現成的程式了,是以我們繼續用pjsua_call_make_call)。

不過還好,pj庫提供了大量的回調,其中一個:on_call_sdp_created,就是在建立sdp後回調上來,由我們自己再修改。比如我們自己定義rtp的端口g_local_port。

void on_call_sdp_created(pjsua_call_id call_id,

                                   pjmedia_sdp_session *sdp,

                                   pj_pool_t *pool,

                                   const pjmedia_sdp_session *rem_sdp)

{

int nPort;

if (sdp != NULL)

pjmedia_sdp_media *m = sdp->media[sdp->media_count-1];

m->desc.port = g_local_port;

pjmedia_sdp_conn *c = sdp->conn;

char* addr;

if (c)

addr= c->addr.ptr;

else

const pj_str_t *hostname;

pj_sockaddr_in tmp_addr;

char *addr;

hostname = pj_gethostname();

pj_sockaddr_in_init(&tmp_addr, hostname, 0);

addr = pj_inet_ntoa(tmp_addr.sin_addr);

sdp->conn = (pjmedia_sdp_conn *)pj_pool_zalloc (pool, sizeof(pjmedia_sdp_conn));

sdp->conn->net_type = pj_str("IN");

sdp->conn->addr_type = pj_str("IP4");

sdp->conn->addr = pj_str(addr);

}

sdp->origin.addr = *pj_gethostname();

同樣,這裡還可以修改payload type等。

這是發起呼叫時的,接收方收到後的回應之後,也會觸發這個回調,自己設定RTP端口,payload type就可以了。

呼叫成功後,雙方建立起連接配接關系,這時需要傳rtp資料了。pjsua把這些工作都放在底層了,不做任何修改,隻需要在發送和接收時,自己做一些處理就行。

先說接收方(參考siprtp.c源碼):

pj_status_t init_local_rtp()

if (m_bInitMedia)

destroy_media();

//g_local_port = local_port;

pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);

    pool = pj_pool_create(&(cp.factory), "test", 1000, 512, NULL);

int status;

//status = pjmedia_endpt_create(&cp.factory,  pjsip_endpt_get_ioqueue(pjsua_get_pjsip_endpt()), 0, &med_endpt);

status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);

status = pjmedia_rtp_session_init(&video.out_sess, 97, pj_rand());

status = pjmedia_rtp_session_init(&video.in_sess, 97, 0);

status = pjmedia_transport_udp_create(med_endpt, NULL, g_local_port,  0, &video.transport);

m_bInitMedia = true;

video.active = true;

return 0;

這段代碼是本地啟動rtp一個端口用來接收視訊資料。

然後,從sdp得到對方發送的ip和端口,調用pjmedia_transport_attach,建立關聯就可以了。

發送方同樣調用上面函數,初始化本地端口,但不需要pjmedia_transport_attach。(假定視訊傳輸是單方向的)

發送動作就比較簡單了,先把要發的資料分包,大小不超過1400,然後pjmedia_rtp_encode_rtp,再pjmedia_transport_send_rtp。

上面還沒有講接收方是怎麼接資料的,這裡也用到了pj提供的回調機制:

status = pjmedia_transport_attach(video.transport, &video, 

//&info.rem_addr, 

&remote_addr,

NULL, 

sizeof(pj_sockaddr_in),

&on_rx_rtp,

NULL);

這裡面的on_rx_rtp就是接收RTP的回調。

video.transport等定義:

struct media_stream

    /* Static: */

    unsigned call_index;    /* Call owner. */

    unsigned media_index;    /* Media index in call. */

    pjmedia_transport   *transport;    /* To send/recv RTP/RTCP */

    /* Active? */

    pj_bool_t active;    /* Non-zero if is in call. */

    /* Current stream info: */

    pjmedia_stream_info si;    /* Current stream info. */

    /* More info: */

    unsigned clock_rate;    /* clock rate */

    unsigned samples_per_frame; /* samples per frame */

    unsigned bytes_per_frame;   /* frame size. */

    /* RTP session: */

    pjmedia_rtp_session out_sess;    /* outgoing RTP session */

    pjmedia_rtp_session in_sess;    /* incoming RTP session */

    /* RTCP stats: */

    pjmedia_rtcp_session rtcp;    /* incoming RTCP session. */

    /* Thread: */

    pj_bool_t thread_quit_flag;  /* Stop media thread. */

    pj_thread_t *thread;    /* Media thread. */

};

struct media_stream video;

源碼在:https://github.com/sxcong/pjsipvideo_demo

視訊源RTSP,可以直接使用IPCAM,比如海康錄影機。

SIP SERVER是開源的resiprocate,編譯出來可直接使用。

DEMO程式是vc2008寫的,包括SIP的登入,發送請求,發送和接收視訊并解碼播放。可在同一台機器上運作兩個執行個體測試。

不過畢竟是DEMO,隻是示範怎麼使用,細節還有很多問題需要修改。

from:http://blog.chinaunix.net/uid-15063109-id-4445165.html

繼續閱讀