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

Reply via email to