#define RTSP_FLAG_OPTS(name, longname) \
{ name, longname, OFFSET(rtsp_flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtsp_flags" }, \
- { "filter_src", "Only receive packets from the negotiated peer IP", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_FILTER_SRC}, 0, 0, DEC, "rtsp_flags" }
+ { "filter_src", "only receive packets from the negotiated peer IP", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_FILTER_SRC}, 0, 0, DEC, "rtsp_flags" }
#define RTSP_MEDIATYPE_OPTS(name, longname) \
{ name, longname, OFFSET(media_type_mask), AV_OPT_TYPE_FLAGS, { .i64 = (1 << (AVMEDIA_TYPE_DATA+1)) - 1 }, INT_MIN, INT_MAX, DEC, "allowed_media_types" }, \
{ "data", "Data", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << AVMEDIA_TYPE_DATA}, 0, 0, DEC, "allowed_media_types" }
#define RTSP_REORDERING_OPTS() \
- { "reorder_queue_size", "Number of packets to buffer for handling of reordered packets", OFFSET(reordering_queue_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC }
+ { "reorder_queue_size", "set number of packets to buffer for handling of reordered packets", OFFSET(reordering_queue_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC }
const AVOption ff_rtsp_options[] = {
- { "initial_pause", "Don't start playing the stream immediately", OFFSET(initial_pause), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
+ { "initial_pause", "do not start playing the stream immediately", OFFSET(initial_pause), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
FF_RTP_FLAG_OPTS(RTSPState, rtp_muxer_flags),
- { "rtsp_transport", "RTSP transport protocols", OFFSET(lower_transport_mask), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC|ENC, "rtsp_transport" }, \
+ { "rtsp_transport", "set RTSP transport protocols", OFFSET(lower_transport_mask), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, DEC|ENC, "rtsp_transport" }, \
{ "udp", "UDP", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_UDP}, 0, 0, DEC|ENC, "rtsp_transport" }, \
{ "tcp", "TCP", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_TCP}, 0, 0, DEC|ENC, "rtsp_transport" }, \
{ "udp_multicast", "UDP multicast", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_UDP_MULTICAST}, 0, 0, DEC, "rtsp_transport" },
{ "http", "HTTP tunneling", 0, AV_OPT_TYPE_CONST, {.i64 = (1 << RTSP_LOWER_TRANSPORT_HTTP)}, 0, 0, DEC, "rtsp_transport" },
- RTSP_FLAG_OPTS("rtsp_flags", "RTSP flags"),
- { "listen", "Wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" },
- RTSP_MEDIATYPE_OPTS("allowed_media_types", "Media types to accept from the server"),
- { "min_port", "Minimum local UDP port", OFFSET(rtp_port_min), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MIN}, 0, 65535, DEC|ENC },
- { "max_port", "Maximum local UDP port", OFFSET(rtp_port_max), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MAX}, 0, 65535, DEC|ENC },
- { "timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies flag listen", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC },
- { "stimeout", "timeout (in micro seconds) of socket i/o operations.", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
+ RTSP_FLAG_OPTS("rtsp_flags", "set RTSP flags"),
+ { "listen", "wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" },
+ { "prefer_tcp", "try RTP via TCP first, if available", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_PREFER_TCP}, 0, 0, DEC|ENC, "rtsp_flags" },
+ RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"),
+ { "min_port", "set minimum local UDP port", OFFSET(rtp_port_min), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MIN}, 0, 65535, DEC|ENC },
+ { "max_port", "set maximum local UDP port", OFFSET(rtp_port_max), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MAX}, 0, 65535, DEC|ENC },
+ { "timeout", "set maximum timeout (in seconds) to wait for incoming connections (-1 is infinite, imply flag listen)", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC },
+ { "stimeout", "set timeout (in microseconds) of socket TCP I/O operations", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
RTSP_REORDERING_OPTS(),
{ "user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC },
{ NULL },
static const AVOption sdp_options[] = {
RTSP_FLAG_OPTS("sdp_flags", "SDP flags"),
- { "custom_io", "Use custom IO", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_CUSTOM_IO}, 0, 0, DEC, "rtsp_flags" },
- { "rtcp_to_source", "Send RTCP packets to the source address of received packets", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_RTCP_TO_SOURCE}, 0, 0, DEC, "rtsp_flags" },
- RTSP_MEDIATYPE_OPTS("allowed_media_types", "Media types to accept from the server"),
+ { "custom_io", "use custom I/O", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_CUSTOM_IO}, 0, 0, DEC, "rtsp_flags" },
+ { "rtcp_to_source", "send RTCP packets to the source address of received packets", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_RTCP_TO_SOURCE}, 0, 0, DEC, "rtsp_flags" },
+ RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"),
RTSP_REORDERING_OPTS(),
{ NULL },
};
static const AVOption rtp_options[] = {
- RTSP_FLAG_OPTS("rtp_flags", "RTP flags"),
+ RTSP_FLAG_OPTS("rtp_flags", "set RTP flags"),
RTSP_REORDERING_OPTS(),
{ NULL },
};
struct RTSPSource **default_include_source_addrs; /**< Source-specific multicast include source IP address (from SDP content) */
int nb_default_exclude_source_addrs; /**< Number of source-specific multicast exclude source IP address (from SDP content) */
struct RTSPSource **default_exclude_source_addrs; /**< Source-specific multicast exclude source IP address (from SDP content) */
+ int seen_rtpmap;
+ int seen_fmtp;
+ char delayed_fmtp[2048];
} SDPParseState;
static void copy_default_source_addrs(struct RTSPSource **addrs, int count,
}
}
+static void parse_fmtp(AVFormatContext *s, RTSPState *rt,
+ int payload_type, const char *line)
+{
+ int i;
+
+ for (i = 0; i < rt->nb_rtsp_streams; i++) {
+ RTSPStream *rtsp_st = rt->rtsp_streams[i];
+ if (rtsp_st->sdp_payload_type == payload_type &&
+ rtsp_st->dynamic_handler &&
+ rtsp_st->dynamic_handler->parse_sdp_a_line) {
+ rtsp_st->dynamic_handler->parse_sdp_a_line(s, i,
+ rtsp_st->dynamic_protocol_context, line);
+ }
+ }
+}
+
static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
int letter, const char *buf)
{
char buf1[64], st_type[64];
const char *p;
enum AVMediaType codec_type;
- int payload_type, i;
+ int payload_type;
AVStream *st;
RTSPStream *rtsp_st;
RTSPSource *rtsp_src;
break;
case 'm':
/* new stream */
- s1->skip_media = 0;
+ s1->skip_media = 0;
+ s1->seen_fmtp = 0;
+ s1->seen_rtpmap = 0;
codec_type = AVMEDIA_TYPE_UNKNOWN;
get_word(st_type, sizeof(st_type), &p);
if (!strcmp(st_type, "audio")) {
st = s->streams[rtsp_st->stream_index];
sdp_parse_rtpmap(s, st, rtsp_st, payload_type, p);
}
+ s1->seen_rtpmap = 1;
+ if (s1->seen_fmtp) {
+ parse_fmtp(s, rt, payload_type, s1->delayed_fmtp);
+ }
} else if (av_strstart(p, "fmtp:", &p) ||
av_strstart(p, "framesize:", &p)) {
- /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */
// let dynamic protocol handlers have a stab at the line.
get_word(buf1, sizeof(buf1), &p);
payload_type = atoi(buf1);
- for (i = 0; i < rt->nb_rtsp_streams; i++) {
- rtsp_st = rt->rtsp_streams[i];
- if (rtsp_st->sdp_payload_type == payload_type &&
- rtsp_st->dynamic_handler &&
- rtsp_st->dynamic_handler->parse_sdp_a_line)
- rtsp_st->dynamic_handler->parse_sdp_a_line(s, i,
- rtsp_st->dynamic_protocol_context, buf);
+ if (s1->seen_rtpmap) {
+ parse_fmtp(s, rt, payload_type, buf);
+ } else {
+ s1->seen_fmtp = 1;
+ av_strlcpy(s1->delayed_fmtp, buf, sizeof(s1->delayed_fmtp));
}
} else if (av_strstart(p, "range:", &p)) {
int64_t start, end;
av_free(s1->default_exclude_source_addrs[i]);
av_freep(&s1->default_exclude_source_addrs);
- rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1));
+ rt->p = av_malloc_array(rt->nb_rtsp_streams + 1, sizeof(struct pollfd) * 2);
if (!rt->p) return AVERROR(ENOMEM);
return 0;
}
s->ctx_flags |= AVFMTCTX_NOHEADER;
if (s->oformat && CONFIG_RTSP_MUXER) {
- int ret = ff_rtp_chain_mux_open((AVFormatContext **)&rtsp_st->transport_priv, s, st,
- rtsp_st->rtp_handle,
+ int ret = ff_rtp_chain_mux_open((AVFormatContext **)&rtsp_st->transport_priv,
+ s, st, rtsp_st->rtp_handle,
RTSP_TCP_MAX_PACKET_SIZE,
rtsp_st->stream_index);
/* Ownership of rtp_handle is passed to the rtp mux context */
rtsp_st->rtp_handle = NULL;
if (ret < 0)
return ret;
+ st->time_base = ((AVFormatContext*)rtsp_st->transport_priv)->streams[0]->time_base;
} else if (rt->transport == RTSP_TRANSPORT_RAW) {
return 0; // Don't need to open any parser here
} else if (rt->transport == RTSP_TRANSPORT_RDT && CONFIG_RTPDEC)
int lower_transport = ff_log2_tab[lower_transport_mask &
~(lower_transport_mask - 1)];
+ if ((lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_TCP))
+ && (rt->rtsp_flags & RTSP_FLAG_PREFER_TCP))
+ lower_transport = RTSP_LOWER_TRANSPORT_TCP;
+
err = ff_rtsp_make_setup_request(s, host, port, lower_transport,
rt->server_type == RTSP_SERVER_REAL ?
real_challenge : NULL);
st2->time_base);
}
}
+ // Make real NTP start time available in AVFormatContext
+ if (s->start_time_realtime == AV_NOPTS_VALUE) {
+ s->start_time_realtime = av_rescale (rtpctx->first_rtcp_ntp_time - (NTP_OFFSET << 32), 1000000, 1LL << 32);
+ if (rtpctx->st) {
+ s->start_time_realtime -=
+ av_rescale (rtpctx->rtcp_ts_offset,
+ (uint64_t) rtpctx->st->time_base.num * 1000000,
+ rtpctx->st->time_base.den);
+ }
+ }
}
if (ret == -RTCP_BYE) {
rt->nb_byes++;