ffmpeg 接收rtp流时占用2个端口的解决办法

  • Post author:
  • Post category:其他


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的代码也很有帮助。



版权声明:本文为wlj1012原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。