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的代碼也很有幫助。