ffmpeg 接收rtp流時佔用2個端口的解決辦法

1. 背景

    在測試 ffmpeg接收 ts over rtp流時,使用工具發了幾個連續端口的rtp流,比如:rtp://192.168.1.11:1234, rtp://192.168.1.11:1235等,結果發現ffmpeg在接收純rtp流時,也將rtcp的端口開啓了。看樣子是繼承了rtsp的做法。

代碼如下:

    rtpproto.c

static int rtp_open(URLContext *h, const char *uri, int flags)
{
    RTPContext *s = h->priv_data;
    ......
    av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port,
                 path, sizeof(path), uri);

	printf("rtp url:%s\n", uri);
    /* extract parameters */
    if (s->rtcp_port < 0)
        s->rtcp_port = rtp_port + 1;
    ......

    if (s->local_rtcpport < 0) {
	            s->local_rtcpport = s->local_rtpport + 1;
	            build_udp_url(s, buf, sizeof(buf),
	                          hostname, s->rtcp_port, s->local_rtcpport,
	                          sources, block);
	            if (ffurl_open_whitelist(&s->rtcp_hd, buf, rtcpflags,
	                                     &h->interrupt_callback, NULL,
	                                     h->protocol_whitelist,         h->protocol_blacklist, h) < 0) {
	                s->local_rtpport = s->local_rtcpport = -1;
	                continue;
	            }
	            break;
	        }
	        build_udp_url(s, buf, sizeof(buf),
	                      hostname, s->rtcp_port, s->local_rtcpport,
	                      sources, block);
	        if (ffurl_open_whitelist(&s->rtcp_hd, buf, rtcpflags, &h->interrupt_callback,
	                                 NULL, h->protocol_whitelist, h->protocol_blacklist, h) < 0)
	            goto fail;
	        break;

  2. 分析

      需要將輸入流 rtsp://xxx 和 rtp://xxx 區分開處理, rtsp流需要開起rtp和rtcp兩個端口; rtp只需要開起一個端口。在RTPContext新加一個參數rtcp_need用來區分輸入流。

3. 代碼示例

  

rtpproto.c

typedef struct RTPContext {
    ......
    int rtcp_port, local_rtpport, local_rtcpport;
    int rtcp_need;
    ......
} RTPContext;
rtpproto.c

static int rtp_open(URLContext *h, const char *uri, int flags)
{
    RTPContext *s = h->priv_data;
    ......

    /* extract parameters */
    if (s->rtcp_port < 0)
        s->rtcp_port = rtp_port + 1;

    if (s->rtcp_need < 0)
    	s->rtcp_need = 0;

    ......

        if (av_find_info_tag(buf, sizeof(buf), "connect", p)) {
            s->connect = strtol(buf, NULL, 10);
        }
	if (av_find_info_tag(buf, sizeof(buf), "rtcp_need", p)) {
            s->rtcp_need = strtol(buf, NULL, 10);
        }

    if (s->rtcp_need == 1)
    {
			
	 if (s->local_rtcpport < 0) {
	      s->local_rtcpport = s->local_rtpport + 1;
         
         .....

         if (ffurl_open_whitelist(&s->rtcp_hd, buf, rtcpflags, &h->interrupt_callback,
	                                 NULL, h->protocol_whitelist, h->protocol_blacklist, h) < 0)
	            goto fail;
	        break;
     }
		
     break;
rtsp.c

int ff_rtsp_make_setup_request(AVFormatContext *s, const char *host, int port,
                              int lower_transport, const char *real_challenge)
{
    RTSPState *rt = s->priv_data;

    ......

        /* first try in specified port range */
            while (j <= rt->rtp_port_max) {
                AVDictionary *opts = map_to_opts(rt);

                ff_url_join(buf, sizeof(buf), "rtp", NULL, host, -1,
                            "?localport=%d&rtcp_need=1", (rtsp_st->sdp_port)?rtsp_st->sdp_port:j);

......

4. 總結

    這個問題本身比較好解決,對熟悉ffmpeg的代碼也很有幫助。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章