Instead of assuming a single payload type per RTSPStream,
store a collection of payload types, along with the necessary
data (indexes, transports, dynamic handlers, etc).
Upon reading the first RTP-UDP packet, set the transport_priv
pointer for the RTSPStream to the transport for the corresponding
payload (via pick_transport_priv), and the rest of the processing
proceeds as usual.
Only tested with RTP-UDP. Most likely breaks RTSP, TCP, RDT,
leaks and/or corrupts data, etc. Clearly, a work-in-progress.
---
libavformat/rtsp.c | 155 ++++++++++++++++++++++++++++++++++++----------------
libavformat/rtsp.h | 30 ++++++----
2 files changed, 129 insertions(+), 56 deletions(-)
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 70f8e21..fe4b4c3 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -176,23 +176,23 @@ static int get_sockaddr(const char *buf, struct
sockaddr_storage *sock)
#if CONFIG_RTPDEC
static void init_rtp_handler(RTPDynamicProtocolHandler *handler,
- RTSPStream *rtsp_st, AVCodecContext *codec)
+ RTSPPayload *payload, AVCodecContext *codec)
{
if (!handler)
return;
if (codec)
codec->codec_id = handler->codec_id;
- rtsp_st->dynamic_handler = handler;
+ payload->dynamic_handler = handler;
if (handler->alloc) {
- rtsp_st->dynamic_protocol_context = handler->alloc();
- if (!rtsp_st->dynamic_protocol_context)
- rtsp_st->dynamic_handler = NULL;
+ payload->dynamic_protocol_context = handler->alloc();
+ if (!payload->dynamic_protocol_context)
+ payload->dynamic_handler = NULL;
}
}
/* parse the rtpmap description: <codec_name>/<clock_rate>[/<other params>] */
static int sdp_parse_rtpmap(AVFormatContext *s,
- AVStream *st, RTSPStream *rtsp_st,
+ AVStream *st, RTSPPayload *pt_ctx,
int payload_type, const char *p)
{
AVCodecContext *codec = st->codec;
@@ -215,12 +215,12 @@ static int sdp_parse_rtpmap(AVFormatContext *s,
if (codec->codec_id == AV_CODEC_ID_NONE) {
RTPDynamicProtocolHandler *handler =
ff_rtp_handler_find_by_name(buf, codec->codec_type);
- init_rtp_handler(handler, rtsp_st, codec);
+ init_rtp_handler(handler, pt_ctx, codec);
/* If no dynamic handler was found, check with the list of standard
* allocated types, if such a stream for some reason happens to
* use a private payload type. This isn't handled in rtpdec.c, since
* the format name from the rtpmap line never is passed into rtpdec. */
- if (!rtsp_st->dynamic_handler)
+ if (!pt_ctx->dynamic_handler)
codec->codec_id = ff_rtp_codec_id(buf, codec->codec_type);
}
@@ -258,9 +258,9 @@ static int sdp_parse_rtpmap(AVFormatContext *s,
default:
break;
}
- if (rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->init)
- rtsp_st->dynamic_handler->init(s, st->index,
- rtsp_st->dynamic_protocol_context);
+ if (pt_ctx->dynamic_handler && pt_ctx->dynamic_handler->init)
+ pt_ctx->dynamic_handler->init(s, st->index,
+ pt_ctx->dynamic_protocol_context);
return 0;
}
@@ -406,11 +406,18 @@ static void sdp_parse_line(AVFormatContext *s,
SDPParseState *s1,
else if (strstr(buf1, "/AVPF") || strstr(buf1, "/SAVPF"))
rtsp_st->feedback = 1;
- /* XXX: handle list of formats */
+ while (*p) {
+ int payload_type;
+ RTSPPayload* pt_ctx = NULL;
get_word(buf1, sizeof(buf1), &p); /* format list */
- rtsp_st->sdp_payload_type = atoi(buf1);
+ payload_type = atoi(buf1);
- if (!strcmp(ff_rtp_enc_name(rtsp_st->sdp_payload_type), "MP2T")) {
+ pt_ctx = av_mallocz(sizeof(RTSPPayload));
+ if (!pt_ctx) return;
+ dynarray_add(&rtsp_st->payload_types, &rtsp_st->nb_payload_types,
pt_ctx);
+ pt_ctx->type = payload_type;
+
+ if (!strcmp(ff_rtp_enc_name(payload_type), "MP2T")) {
/* no corresponding stream */
if (rt->transport == RTSP_TRANSPORT_RAW) {
if (!rt->ts && CONFIG_RTPDEC)
@@ -418,10 +425,10 @@ static void sdp_parse_line(AVFormatContext *s,
SDPParseState *s1,
} else {
RTPDynamicProtocolHandler *handler;
handler = ff_rtp_handler_find_by_id(
- rtsp_st->sdp_payload_type, AVMEDIA_TYPE_DATA);
- init_rtp_handler(handler, rtsp_st, NULL);
+ payload_type, AVMEDIA_TYPE_DATA);
+ init_rtp_handler(handler, pt_ctx, NULL);
if (handler && handler->init)
- handler->init(s, -1, rtsp_st->dynamic_protocol_context);
+ handler->init(s, -1, pt_ctx->dynamic_protocol_context);
}
} else if (rt->server_type == RTSP_SERVER_WMS &&
codec_type == AVMEDIA_TYPE_DATA) {
@@ -434,22 +441,24 @@ static void sdp_parse_line(AVFormatContext *s,
SDPParseState *s1,
st->id = rt->nb_rtsp_streams - 1;
rtsp_st->stream_index = st->index;
st->codec->codec_type = codec_type;
- if (rtsp_st->sdp_payload_type < RTP_PT_PRIVATE) {
+ pt_ctx->index = st->index;
+ if (payload_type < RTP_PT_PRIVATE) {
RTPDynamicProtocolHandler *handler;
/* if standard payload type, we can find the codec right now */
- ff_rtp_get_codec_info(st->codec, rtsp_st->sdp_payload_type);
+ ff_rtp_get_codec_info(st->codec, payload_type);
if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
st->codec->sample_rate > 0)
avpriv_set_pts_info(st, 32, 1, st->codec->sample_rate);
/* Even static payload types may need a custom depacketizer */
handler = ff_rtp_handler_find_by_id(
- rtsp_st->sdp_payload_type,
st->codec->codec_type);
- init_rtp_handler(handler, rtsp_st, st->codec);
+ payload_type, st->codec->codec_type);
+ init_rtp_handler(handler, pt_ctx, st->codec);
if (handler && handler->init)
handler->init(s, st->index,
- rtsp_st->dynamic_protocol_context);
+ pt_ctx->dynamic_protocol_context);
}
}
+ }
/* put a default control url */
av_strlcpy(rtsp_st->control_url, rt->control_uri,
sizeof(rtsp_st->control_url));
@@ -485,8 +494,15 @@ static void sdp_parse_line(AVFormatContext *s,
SDPParseState *s1,
payload_type = atoi(buf1);
rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
if (rtsp_st->stream_index >= 0) {
- st = s->streams[rtsp_st->stream_index];
- sdp_parse_rtpmap(s, st, rtsp_st, payload_type, p);
+ int j;
+ for (j = 0; j < rtsp_st->nb_payload_types; j++) {
+ RTSPPayload *pt_ctx = rtsp_st->payload_types[j];
+ if (payload_type == pt_ctx->type) {
+ st = s->streams[pt_ctx->index];
+ sdp_parse_rtpmap(s, st, pt_ctx, payload_type, p);
+ break;
+ }
+ }
}
} else if (av_strstart(p, "fmtp:", &p) ||
av_strstart(p, "framesize:", &p)) {
@@ -495,12 +511,16 @@ static void sdp_parse_line(AVFormatContext *s,
SDPParseState *s1,
get_word(buf1, sizeof(buf1), &p);
payload_type = atoi(buf1);
for (i = 0; i < rt->nb_rtsp_streams; i++) {
+ int j;
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);
+ for (j = 0; j < rtsp_st->nb_payload_types; j++) {
+ RTSPPayload *pt_ctx = rtsp_st->payload_types[j];
+ if (pt_ctx->type == payload_type &&
+ pt_ctx->dynamic_handler &&
+ pt_ctx->dynamic_handler->parse_sdp_a_line)
+ pt_ctx->dynamic_handler->parse_sdp_a_line(s,
+ i, pt_ctx->dynamic_protocol_context, buf);
+ }
}
} else if (av_strstart(p, "range:", &p)) {
int64_t start, end;
@@ -572,11 +592,11 @@ static void sdp_parse_line(AVFormatContext *s,
SDPParseState *s1,
if (rt->server_type == RTSP_SERVER_REAL)
ff_real_parse_sdp_a_line(s, rtsp_st->stream_index, p);
- if (rtsp_st->dynamic_handler &&
+ /*if (rtsp_st->dynamic_handler &&
rtsp_st->dynamic_handler->parse_sdp_a_line)
rtsp_st->dynamic_handler->parse_sdp_a_line(s,
rtsp_st->stream_index,
- rtsp_st->dynamic_protocol_context, buf);
+ rtsp_st->dynamic_protocol_context, buf);*/
}
}
break;
@@ -684,9 +704,14 @@ void ff_rtsp_close_streams(AVFormatContext *s)
for (i = 0; i < rt->nb_rtsp_streams; i++) {
rtsp_st = rt->rtsp_streams[i];
if (rtsp_st) {
- if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
- rtsp_st->dynamic_handler->free(
- rtsp_st->dynamic_protocol_context);
+ int k;
+ for (k = 0; k < rtsp_st->nb_payload_types; k++) {
+ RTSPPayload *pt_ctx = rtsp_st->payload_types[k];
+ if (pt_ctx->dynamic_handler &&
+ pt_ctx->dynamic_protocol_context)
+ pt_ctx->dynamic_handler->free(
+ pt_ctx->dynamic_protocol_context);
+ }
for (j = 0; j < rtsp_st->nb_include_source_addrs; j++)
av_free(rtsp_st->include_source_addrs[j]);
av_freep(&rtsp_st->include_source_addrs);
@@ -712,6 +737,7 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s,
RTSPStream *rtsp_st)
RTSPState *rt = s->priv_data;
AVStream *st = NULL;
int reordering_queue_size = rt->reordering_queue_size;
+ int i;
if (reordering_queue_size < 0) {
if (rt->lower_transport == RTSP_LOWER_TRANSPORT_TCP || !s->max_delay)
reordering_queue_size = 0;
@@ -737,21 +763,37 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s,
RTSPStream *rtsp_st)
} 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)
- rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index,
- rtsp_st->dynamic_protocol_context,
- rtsp_st->dynamic_handler);
+ for (i = 0; i < rtsp_st->nb_payload_types; i++) {
+ RTSPPayload *pt_ctx = rtsp_st->payload_types[i];
+ pt_ctx->transport_priv = ff_rdt_parse_open(s, pt_ctx->index,
+ pt_ctx->dynamic_protocol_context,
+ pt_ctx->dynamic_handler);
+ if (!pt_ctx->transport_priv) {
+ return AVERROR(ENOMEM);
+ }
+ }
else if (CONFIG_RTPDEC)
- rtsp_st->transport_priv = ff_rtp_parse_open(s, st,
- rtsp_st->sdp_payload_type,
- reordering_queue_size);
+ for (i = 0; i < rtsp_st->nb_payload_types; i++) {
+ RTSPPayload *pt_ctx = rtsp_st->payload_types[i];
+ pt_ctx->transport_priv = ff_rtp_parse_open(s,
+ s->streams[pt_ctx->index],
+ pt_ctx->type,
+ reordering_queue_size);
+ if (!pt_ctx->transport_priv) {
+ return AVERROR(ENOMEM);
+ }
+ }
- if (!rtsp_st->transport_priv) {
+ if (s->oformat && !rtsp_st->transport_priv) {
return AVERROR(ENOMEM);
} else if (rt->transport == RTSP_TRANSPORT_RTP && CONFIG_RTPDEC) {
- if (rtsp_st->dynamic_handler) {
- ff_rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv,
-
rtsp_st->dynamic_protocol_context,
- rtsp_st->dynamic_handler);
+ for (i = 0; i < rtsp_st->nb_payload_types; i++) {
+ RTSPPayload *pt_ctx = rtsp_st->payload_types[i];
+ if (pt_ctx->dynamic_handler) {
+ ff_rtp_parse_set_dynamic_protocol(pt_ctx->transport_priv,
+ pt_ctx->dynamic_protocol_context,
+ pt_ctx->dynamic_handler);
+ }
}
if (rtsp_st->crypto_suite[0])
ff_rtp_parse_set_crypto(rtsp_st->transport_priv,
@@ -1922,10 +1964,14 @@ static int pick_stream(AVFormatContext *s, RTSPStream
**rtsp_st,
}
} else {
for (i = 0; i < rt->nb_rtsp_streams; i++) {
- if ((buf[1] & 0x7f) == rt->rtsp_streams[i]->sdp_payload_type) {
+ int j;
+ for (j = 0; j < rt->rtsp_streams[i]->nb_payload_types; j++) {
+ RTSPPayload *pt_ctx =
rt->rtsp_streams[i]->payload_types[j];
+ if ((buf[1] & 0x7f) == pt_ctx->type) {
*rtsp_st = rt->rtsp_streams[i];
return len;
}
+ }
}
}
}
@@ -1933,6 +1979,20 @@ static int pick_stream(AVFormatContext *s, RTSPStream
**rtsp_st,
return AVERROR(EAGAIN);
}
+static void* pick_transport_priv(RTSPStream *rtsp_st, const uint8_t *buf, int
len)
+{
+ int i;
+ if (len < 8) return NULL;
+ if (RTP_PT_IS_RTCP(buf[1])) return NULL;
+ for (i = 0; i < rtsp_st->nb_payload_types; i++) {
+ RTSPPayload *pt_ctx = rtsp_st->payload_types[i];
+ if ((buf[1] & 0x7f) == pt_ctx->type) {
+ return pt_ctx->transport_priv;
+ }
+ }
+ return NULL;
+}
+
int ff_rtsp_fetch_packet(AVFormatContext *s, AVPacket *pkt)
{
RTSPState *rt = s->priv_data;
@@ -2007,6 +2067,9 @@ redo:
case RTSP_LOWER_TRANSPORT_UDP:
case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
len = udp_read_packet(s, &rtsp_st, rt->recvbuf, RECVBUF_SIZE,
wait_end);
+ if (len > 0 && !rtsp_st->transport_priv && rt->transport ==
RTSP_TRANSPORT_RTP) {
+ rtsp_st->transport_priv = pick_transport_priv(rtsp_st,
rt->recvbuf, len);
+ }
if (len > 0 && rtsp_st->transport_priv && rt->transport ==
RTSP_TRANSPORT_RTP)
ff_rtp_check_and_send_back_rr(rtsp_st->transport_priv,
rtsp_st->rtp_handle, NULL, len);
break;
diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h
index 7a910b0..4b2c445 100644
--- a/libavformat/rtsp.h
+++ b/libavformat/rtsp.h
@@ -408,6 +408,22 @@ typedef struct RTSPSource {
char addr[128]; /**< Source-specific multicast include source IP address
(from SDP content) */
} RTSPSource;
+typedef struct RTSPPayload {
+ int type; /**< payload type */
+ int index; /**< corresponding stream index, if any. -1 if none
(MPEG2TS case) */
+
+ /** The following are used for dynamic protocols (rtpdec_*.c/rdt.c) */
+ //@{
+ /** handler structure */
+ RTPDynamicProtocolHandler *dynamic_handler;
+
+ /** private data associated with the dynamic protocol */
+ PayloadContext *dynamic_protocol_context;
+ //@}
+
+ void *transport_priv;
+} RTSPPayload;
+
/**
* Describe a single stream, as identified by a single m= line block in the
* SDP content. In the case of RDT, one RTSPStream can represent multiple
@@ -436,16 +452,6 @@ typedef struct RTSPStream {
int nb_exclude_source_addrs; /**< Number of source-specific multicast
exclude source IP addresses (from SDP content) */
struct RTSPSource **exclude_source_addrs; /**< Source-specific multicast
exclude source IP addresses (from SDP content) */
int sdp_ttl; /**< IP Time-To-Live (from SDP content) */
- int sdp_payload_type; /**< payload type */
- //@}
-
- /** The following are used for dynamic protocols (rtpdec_*.c/rdt.c) */
- //@{
- /** handler structure */
- RTPDynamicProtocolHandler *dynamic_handler;
-
- /** private data associated with the dynamic protocol */
- PayloadContext *dynamic_protocol_context;
//@}
/** Enable sending RTCP feedback messages according to RFC 4585 */
@@ -453,6 +459,10 @@ typedef struct RTSPStream {
char crypto_suite[40];
char crypto_params[100];
+
+ int nb_payload_types;
+ RTSPPayload **payload_types;
+
} RTSPStream;
void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf,
--
1.7.9.5
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel