rtsp: Don't expose streams that won't be useful

Message ID 1333741401-27244-1-git-send-email-martin@martin.st
State Superseded
Headers show

Commit Message

Martin Storsjö April 6, 2012, 7:43 p.m.
This avoids having to try to wait for data in
avformat_find_stream_info that we won't be able to decode anyway.
---
 libavformat/rtsp.c |   28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

Comments

Martin Storsjö April 6, 2012, 7:57 p.m. | #1
On Fri, 6 Apr 2012, Martin Storsjö wrote:

> This avoids having to try to wait for data in
> avformat_find_stream_info that we won't be able to decode anyway.
> ---
> libavformat/rtsp.c |   28 ++++++++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
>
> diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
> index c94ef02..c9c366f 100644
> --- a/libavformat/rtsp.c
> +++ b/libavformat/rtsp.c
> @@ -278,6 +278,32 @@ int ff_rtsp_next_attr_and_value(const char **p, char *attr, int attr_size,
>     return 0;
> }
>
> +static void free_uninitialized_stream(AVFormatContext *s)
> +{
> +    RTSPState *rt = s->priv_data;
> +    RTSPStream *rtsp_st;
> +    AVStream *st;
> +
> +    if (rt->nb_rtsp_streams <= 0)
> +        return;
> +    rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
> +    if (rtsp_st->stream_index < 0)
> +        return;
> +    st = s->streams[rtsp_st->stream_index];
> +    if (st->codec->codec_id != CODEC_ID_NONE)
> +        return;
> +    if (rtsp_st->dynamic_handler)
> +        return;
> +    /* Previous stream never got a codec id assigned, and isn't handled
> +     * by any dynamic handler, thus don't expose it */
> +    av_free(st->codec);
> +    av_free(st->info);
> +    av_free(st);
> +    av_free(rtsp_st);
> +    rt->nb_rtsp_streams--;
> +    s->nb_streams--;
> +}
> +
> typedef struct SDPParseState {
>     /* SDP only */
>     struct sockaddr_storage default_ip;
> @@ -354,6 +380,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
>             s1->skip_media = 1;
>             return;
>         }
> +        free_uninitialized_stream(s);
>         rtsp_st = av_mallocz(sizeof(RTSPStream));
>         if (!rtsp_st)
>             return;
> @@ -523,6 +550,7 @@ int ff_sdp_parse(AVFormatContext *s, const char *content)
>         if (*p == '\n')
>             p++;
>     }
> +    free_uninitialized_stream(s);
>     rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1));
>     if (!rt->p) return AVERROR(ENOMEM);
>     return 0;
> -- 
> 1.7.9.4

Hmm, this still isn't totally right - for MS-RTSP/UDP, we need the data 
stream, since all the packets actually are sent over this connection, 
according to this code snippet:

         /*
          * WMS serves all UDP data over a single connection, the RTX, which
          * isn't necessarily the first in the SDP but has to be the first
          * to be set up, else the second/third SETUP will fail with a 461.
          */
         if (lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
              rt->server_type == RTSP_SERVER_WMS) {
             if (i == 0) {
                 /* rtx first */
                 for (rtx = 0; rtx < rt->nb_rtsp_streams; rtx++) {
                     int len = strlen(rt->rtsp_streams[rtx]->control_url);
                     if (len >= 4 &&
                         !strcmp(rt->rtsp_streams[rtx]->control_url + len - 4,
                                 "/rtx"))
                         break;
                 }
                 if (rtx == rt->nb_rtsp_streams)
                     return -1; /* no RTX found */
                 rtsp_st = rt->rtsp_streams[rtx];
             } else
                 rtsp_st = rt->rtsp_streams[i > rtx ? i : i - 1];
         } else
             rtsp_st = rt->rtsp_streams[i];

This stream of course doesn't have to be exposed to the caller. I'll see 
if there's a neater way of handling it...

// Martin

Patch

diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index c94ef02..c9c366f 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -278,6 +278,32 @@  int ff_rtsp_next_attr_and_value(const char **p, char *attr, int attr_size,
     return 0;
 }
 
+static void free_uninitialized_stream(AVFormatContext *s)
+{
+    RTSPState *rt = s->priv_data;
+    RTSPStream *rtsp_st;
+    AVStream *st;
+
+    if (rt->nb_rtsp_streams <= 0)
+        return;
+    rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1];
+    if (rtsp_st->stream_index < 0)
+        return;
+    st = s->streams[rtsp_st->stream_index];
+    if (st->codec->codec_id != CODEC_ID_NONE)
+        return;
+    if (rtsp_st->dynamic_handler)
+        return;
+    /* Previous stream never got a codec id assigned, and isn't handled
+     * by any dynamic handler, thus don't expose it */
+    av_free(st->codec);
+    av_free(st->info);
+    av_free(st);
+    av_free(rtsp_st);
+    rt->nb_rtsp_streams--;
+    s->nb_streams--;
+}
+
 typedef struct SDPParseState {
     /* SDP only */
     struct sockaddr_storage default_ip;
@@ -354,6 +380,7 @@  static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
             s1->skip_media = 1;
             return;
         }
+        free_uninitialized_stream(s);
         rtsp_st = av_mallocz(sizeof(RTSPStream));
         if (!rtsp_st)
             return;
@@ -523,6 +550,7 @@  int ff_sdp_parse(AVFormatContext *s, const char *content)
         if (*p == '\n')
             p++;
     }
+    free_uninitialized_stream(s);
     rt->p = av_malloc(sizeof(struct pollfd)*2*(rt->nb_rtsp_streams+1));
     if (!rt->p) return AVERROR(ENOMEM);
     return 0;