Browse code

rtsp: Add listen mode

This makes the RTSP demuxer act as a server, listening for an
incoming connection.

Signed-off-by: Martin Storsjö <martin@martin.st>

Jordi Ortiz authored on 2012/07/11 02:36:11
Showing 7 changed files
... ...
@@ -31,6 +31,7 @@ version <next>:
31 31
 - join audio filter
32 32
 - audio channel mapping filter
33 33
 - Microsoft ATC Screen decoder
34
+- RTSP listen mode
34 35
 
35 36
 
36 37
 version 0.8:
... ...
@@ -347,6 +347,8 @@ Flags for @code{rtsp_flags}:
347 347
 @table @option
348 348
 @item filter_src
349 349
 Accept packets only from negotiated peer address and port.
350
+@item listen
351
+Act as a server, listening for an incoming connection.
350 352
 @end table
351 353
 
352 354
 When receiving data over UDP, the demuxer tries to reorder received packets
... ...
@@ -379,6 +381,12 @@ To send a stream in realtime to a RTSP server, for others to watch:
379 379
 avconv -re -i @var{input} -f rtsp -muxdelay 0.1 rtsp://server/live.sdp
380 380
 @end example
381 381
 
382
+To receive a stream in realtime:
383
+
384
+@example
385
+avconv -rtsp_flags listen -i rtsp://ownaddress/live.sdp @var{output}
386
+@end example
387
+
382 388
 @section sap
383 389
 
384 390
 Session Announcement Protocol (RFC 2974). This is not technically a
... ...
@@ -63,7 +63,8 @@
63 63
 
64 64
 #define RTSP_FLAG_OPTS(name, longname) \
65 65
     { name, longname, OFFSET(rtsp_flags), AV_OPT_TYPE_FLAGS, {0}, INT_MIN, INT_MAX, DEC, "rtsp_flags" }, \
66
-    { "filter_src", "Only receive packets from the negotiated peer IP", 0, AV_OPT_TYPE_CONST, {RTSP_FLAG_FILTER_SRC}, 0, 0, DEC, "rtsp_flags" }
66
+    { "filter_src", "Only receive packets from the negotiated peer IP", 0, AV_OPT_TYPE_CONST, {RTSP_FLAG_FILTER_SRC}, 0, 0, DEC, "rtsp_flags" }, \
67
+    { "listen", "Wait for incoming connections", 0, AV_OPT_TYPE_CONST, {RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" }
67 68
 
68 69
 #define RTSP_MEDIATYPE_OPTS(name, longname) \
69 70
     { name, longname, OFFSET(media_type_mask), AV_OPT_TYPE_FLAGS, { (1 << (AVMEDIA_TYPE_DATA+1)) - 1 }, INT_MIN, INT_MAX, DEC, "allowed_media_types" }, \
... ...
@@ -83,6 +84,7 @@ const AVOption ff_rtsp_options[] = {
83 83
     RTSP_MEDIATYPE_OPTS("allowed_media_types", "Media types to accept from the server"),
84 84
     { "min_port", "Minimum local UDP port", OFFSET(rtp_port_min), AV_OPT_TYPE_INT, {RTSP_RTP_PORT_MIN}, 0, 65535, DEC|ENC },
85 85
     { "max_port", "Maximum local UDP port", OFFSET(rtp_port_max), AV_OPT_TYPE_INT, {RTSP_RTP_PORT_MAX}, 0, 65535, DEC|ENC },
86
+    { "timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies flag listen", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {-1}, INT_MIN, INT_MAX, DEC },
86 87
     { NULL },
87 88
 };
88 89
 
... ...
@@ -1714,14 +1716,24 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
1714 1714
             }
1715 1715
 #if CONFIG_RTSP_DEMUXER
1716 1716
             if (tcp_fd != -1 && p[0].revents & POLLIN) {
1717
-                RTSPMessageHeader reply;
1718
-
1719
-                ret = ff_rtsp_read_reply(s, &reply, NULL, 0, NULL);
1720
-                if (ret < 0)
1721
-                    return ret;
1722
-                /* XXX: parse message */
1723
-                if (rt->state != RTSP_STATE_STREAMING)
1724
-                    return 0;
1717
+                if (rt->rtsp_flags & RTSP_FLAG_LISTEN) {
1718
+                    if (rt->state == RTSP_STATE_STREAMING) {
1719
+                        if (!ff_rtsp_parse_streaming_commands(s))
1720
+                            return AVERROR_EOF;
1721
+                        else
1722
+                            av_log(s, AV_LOG_WARNING,
1723
+                                   "Unable to answer to TEARDOWN\n");
1724
+                    } else
1725
+                        return 0;
1726
+                } else {
1727
+                    RTSPMessageHeader reply;
1728
+                    ret = ff_rtsp_read_reply(s, &reply, NULL, 0, NULL);
1729
+                    if (ret < 0)
1730
+                        return ret;
1731
+                    /* XXX: parse message */
1732
+                    if (rt->state != RTSP_STATE_STREAMING)
1733
+                        return 0;
1734
+                }
1725 1735
             }
1726 1736
 #endif
1727 1737
         } else if (n == 0 && ++timeout_cnt >= MAX_TIMEOUTS) {
... ...
@@ -372,11 +372,17 @@ typedef struct RTSPState {
372 372
      * Minimum and maximum local UDP ports.
373 373
      */
374 374
     int rtp_port_min, rtp_port_max;
375
+
376
+    /**
377
+     * Timeout to wait for incoming connections.
378
+     */
379
+    int initial_timeout;
375 380
 } RTSPState;
376 381
 
377 382
 #define RTSP_FLAG_FILTER_SRC  0x1    /**< Filter incoming UDP packets -
378 383
                                           receive packets only from the right
379 384
                                           source address and port. */
385
+#define RTSP_FLAG_LISTEN 0x2         /**< Wait for incoming connections. */
380 386
 
381 387
 /**
382 388
  * Describe a single stream, as identified by a single m= line block in the
... ...
@@ -529,6 +535,12 @@ int ff_rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply);
529 529
 int ff_rtsp_setup_output_streams(AVFormatContext *s, const char *addr);
530 530
 
531 531
 /**
532
+ * Parse RTSP commands (OPTIONS, PAUSE and TEARDOWN) during streaming in
533
+ * listen mode.
534
+ */
535
+int ff_rtsp_parse_streaming_commands(AVFormatContext *s);
536
+
537
+/**
532 538
  * Parse an SDP description of streams by populating an RTSPState struct
533 539
  * within the AVFormatContext; also allocate the RTP streams and the
534 540
  * pollfd array used for UDP streams.
... ...
@@ -37,4 +37,18 @@ RTSP_STATUS_SERVICE         =503, /**< Service Unavailable */
37 37
 RTSP_STATUS_VERSION         =505, /**< RTSP Version not supported */
38 38
 };
39 39
 
40
+enum RTSPMethod {
41
+    DESCRIBE,
42
+    ANNOUNCE,
43
+    OPTIONS,
44
+    SETUP,
45
+    PLAY,
46
+    PAUSE,
47
+    TEARDOWN,
48
+    GET_PARAMETER,
49
+    SET_PARAMETER,
50
+    REDIRECT,
51
+    RECORD,
52
+    UNKNOWN = -1,
53
+};
40 54
 #endif /* AVFORMAT_RTSPCODES_H */
... ...
@@ -22,6 +22,7 @@
22 22
 #include "libavutil/avstring.h"
23 23
 #include "libavutil/intreadwrite.h"
24 24
 #include "libavutil/mathematics.h"
25
+#include "libavutil/random_seed.h"
25 26
 #include "avformat.h"
26 27
 
27 28
 #include "internal.h"
... ...
@@ -31,11 +32,30 @@
31 31
 #include "rdt.h"
32 32
 #include "url.h"
33 33
 
34
+static const struct RTSPStatusMessage {
35
+    enum RTSPStatusCode code;
36
+    const char *message;
37
+} status_messages[] = {
38
+    { RTSP_STATUS_OK,             "OK"                               },
39
+    { RTSP_STATUS_METHOD,         "Method Not Allowed"               },
40
+    { RTSP_STATUS_BANDWIDTH,      "Not Enough Bandwidth"             },
41
+    { RTSP_STATUS_SESSION,        "Session Not Found"                },
42
+    { RTSP_STATUS_STATE,          "Method Not Valid in This State"   },
43
+    { RTSP_STATUS_AGGREGATE,      "Aggregate operation not allowed"  },
44
+    { RTSP_STATUS_ONLY_AGGREGATE, "Only aggregate operation allowed" },
45
+    { RTSP_STATUS_TRANSPORT,      "Unsupported transport"            },
46
+    { RTSP_STATUS_INTERNAL,       "Internal Server Error"            },
47
+    { RTSP_STATUS_SERVICE,        "Service Unavailable"              },
48
+    { RTSP_STATUS_VERSION,        "RTSP Version not supported"       },
49
+    { 0,                          "NULL"                             }
50
+};
51
+
34 52
 static int rtsp_read_close(AVFormatContext *s)
35 53
 {
36 54
     RTSPState *rt = s->priv_data;
37 55
 
38
-    ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
56
+    if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN))
57
+        ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
39 58
 
40 59
     ff_rtsp_close_streams(s);
41 60
     ff_rtsp_close_connections(s);
... ...
@@ -45,6 +65,429 @@ static int rtsp_read_close(AVFormatContext *s)
45 45
     return 0;
46 46
 }
47 47
 
48
+static inline int read_line(AVFormatContext *s, char *rbuf, const int rbufsize,
49
+                            int *rbuflen)
50
+{
51
+    RTSPState *rt = s->priv_data;
52
+    int idx       = 0;
53
+    int ret       = 0;
54
+    *rbuflen      = 0;
55
+
56
+    do {
57
+        ret = ffurl_read_complete(rt->rtsp_hd, rbuf + idx, 1);
58
+        if (ret < 0)
59
+            return ret;
60
+        if (rbuf[idx] == '\r') {
61
+            /* Ignore */
62
+        } else if (rbuf[idx] == '\n') {
63
+            rbuf[idx] = '\0';
64
+            *rbuflen  = idx;
65
+            return 0;
66
+        } else
67
+            idx++;
68
+    } while (idx < rbufsize);
69
+    av_log(s, AV_LOG_ERROR, "Message too long\n");
70
+    return AVERROR(EIO);
71
+}
72
+
73
+static int rtsp_send_reply(AVFormatContext *s, enum RTSPStatusCode code,
74
+                           const char *extracontent, uint16_t seq)
75
+{
76
+    RTSPState *rt = s->priv_data;
77
+    char message[4096];
78
+    int index = 0;
79
+    while (status_messages[index].code) {
80
+        if (status_messages[index].code == code) {
81
+            snprintf(message, sizeof(message), "RTSP/1.0 %d %s\r\n",
82
+                     code, status_messages[index].message);
83
+            break;
84
+        }
85
+        index++;
86
+    }
87
+    if (!status_messages[index].code)
88
+        return AVERROR(EINVAL);
89
+    av_strlcatf(message, sizeof(message), "CSeq: %d\r\n", seq);
90
+    av_strlcatf(message, sizeof(message), "Server: %s\r\n", LIBAVFORMAT_IDENT);
91
+    if (extracontent)
92
+        av_strlcat(message, extracontent, sizeof(message));
93
+    av_strlcat(message, "\r\n", sizeof(message));
94
+    av_dlog(s, "Sending response:\n%s", message);
95
+    ffurl_write(rt->rtsp_hd, message, strlen(message));
96
+
97
+    return 0;
98
+}
99
+
100
+static inline int check_sessionid(AVFormatContext *s,
101
+                                  RTSPMessageHeader *request)
102
+{
103
+    RTSPState *rt = s->priv_data;
104
+    unsigned char *session_id = rt->session_id;
105
+    if (!session_id[0]) {
106
+        av_log(s, AV_LOG_WARNING, "There is no session-id at the moment\n");
107
+        return 0;
108
+    }
109
+    if (strcmp(session_id, request->session_id)) {
110
+        av_log(s, AV_LOG_ERROR, "Unexpected session-id %s\n",
111
+               request->session_id);
112
+        rtsp_send_reply(s, RTSP_STATUS_SESSION, NULL, request->seq);
113
+        return AVERROR_STREAM_NOT_FOUND;
114
+    }
115
+    return 0;
116
+}
117
+
118
+static inline int rtsp_read_request(AVFormatContext *s,
119
+                                    RTSPMessageHeader *request,
120
+                                    const char *method)
121
+{
122
+    RTSPState *rt = s->priv_data;
123
+    char rbuf[1024];
124
+    int rbuflen, ret;
125
+    do {
126
+        ret = read_line(s, rbuf, sizeof(rbuf), &rbuflen);
127
+        if (ret)
128
+            return ret;
129
+        if (rbuflen > 1) {
130
+            av_dlog(s, "Parsing[%d]: %s\n", rbuflen, rbuf);
131
+            ff_rtsp_parse_line(request, rbuf, rt, method);
132
+        }
133
+    } while (rbuflen > 0);
134
+    if (request->seq != rt->seq + 1) {
135
+        av_log(s, AV_LOG_ERROR, "Unexpected Sequence number %d\n",
136
+               request->seq);
137
+        return AVERROR(EINVAL);
138
+    }
139
+    if (rt->session_id[0] && strcmp(method, "OPTIONS")) {
140
+        ret = check_sessionid(s, request);
141
+        if (ret)
142
+            return ret;
143
+    }
144
+
145
+    return 0;
146
+}
147
+
148
+static int rtsp_read_announce(AVFormatContext *s)
149
+{
150
+    RTSPState *rt             = s->priv_data;
151
+    RTSPMessageHeader request = { 0 };
152
+    char sdp[4096];
153
+    int  ret;
154
+
155
+    ret = rtsp_read_request(s, &request, "ANNOUNCE");
156
+    if (ret)
157
+        return ret;
158
+    rt->seq++;
159
+    if (strcmp(request.content_type, "application/sdp")) {
160
+        av_log(s, AV_LOG_ERROR, "Unexpected content type %s\n",
161
+               request.content_type);
162
+        rtsp_send_reply(s, RTSP_STATUS_SERVICE, NULL, request.seq);
163
+        return AVERROR_OPTION_NOT_FOUND;
164
+    }
165
+    if (request.content_length && request.content_length < sizeof(sdp) - 1) {
166
+        /* Read SDP */
167
+        if (ffurl_read_complete(rt->rtsp_hd, sdp, request.content_length)
168
+            < request.content_length) {
169
+            av_log(s, AV_LOG_ERROR,
170
+                   "Unable to get complete SDP Description in ANNOUNCE\n");
171
+            rtsp_send_reply(s, RTSP_STATUS_INTERNAL, NULL, request.seq);
172
+            return AVERROR(EIO);
173
+        }
174
+        sdp[request.content_length] = '\0';
175
+        av_log(s, AV_LOG_VERBOSE, "SDP: %s\n", sdp);
176
+        ret = ff_sdp_parse(s, sdp);
177
+        if (ret)
178
+            return ret;
179
+        rtsp_send_reply(s, RTSP_STATUS_OK, NULL, request.seq);
180
+        return 0;
181
+    }
182
+    av_log(s, AV_LOG_ERROR,
183
+           "Content-Length header value exceeds sdp allocated buffer (4KB)\n");
184
+    rtsp_send_reply(s, RTSP_STATUS_INTERNAL,
185
+                    "Content-Length exceeds buffer size", request.seq);
186
+    return AVERROR(EIO);
187
+}
188
+
189
+static int rtsp_read_options(AVFormatContext *s)
190
+{
191
+    RTSPState *rt             = s->priv_data;
192
+    RTSPMessageHeader request = { 0 };
193
+    int ret                   = 0;
194
+
195
+    /* Parsing headers */
196
+    ret = rtsp_read_request(s, &request, "OPTIONS");
197
+    if (ret)
198
+        return ret;
199
+    rt->seq++;
200
+    /* Send Reply */
201
+    rtsp_send_reply(s, RTSP_STATUS_OK,
202
+                    "Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, RECORD\r\n",
203
+                    request.seq);
204
+    return 0;
205
+}
206
+
207
+static int rtsp_read_setup(AVFormatContext *s, char* host, char *controlurl)
208
+{
209
+    RTSPState *rt             = s->priv_data;
210
+    RTSPMessageHeader request = { 0 };
211
+    int ret                   = 0;
212
+    char url[1024];
213
+    RTSPStream *rtsp_st;
214
+    char responseheaders[1024];
215
+    int localport    = -1;
216
+    int transportidx = 0;
217
+    int streamid     = 0;
218
+
219
+    ret = rtsp_read_request(s, &request, "SETUP");
220
+    if (ret)
221
+        return ret;
222
+    rt->seq++;
223
+    if (!request.nb_transports) {
224
+        av_log(s, AV_LOG_ERROR, "No transport defined in SETUP\n");
225
+        return AVERROR_INVALIDDATA;
226
+    }
227
+    for (transportidx = 0; transportidx < request.nb_transports;
228
+         transportidx++) {
229
+        if (!request.transports[transportidx].mode_record ||
230
+            (request.transports[transportidx].lower_transport !=
231
+             RTSP_LOWER_TRANSPORT_UDP &&
232
+             request.transports[transportidx].lower_transport !=
233
+             RTSP_LOWER_TRANSPORT_TCP)) {
234
+            av_log(s, AV_LOG_ERROR, "mode=record/receive not set or transport"
235
+                   " protocol not supported (yet)\n");
236
+            return AVERROR_INVALIDDATA;
237
+        }
238
+    }
239
+    if (request.nb_transports > 1)
240
+        av_log(s, AV_LOG_WARNING, "More than one transport not supported, "
241
+               "using first of all\n");
242
+    for (streamid = 0; streamid < rt->nb_rtsp_streams; streamid++) {
243
+        if (!strcmp(rt->rtsp_streams[streamid]->control_url,
244
+                    controlurl))
245
+            break;
246
+    }
247
+    if (streamid == rt->nb_rtsp_streams) {
248
+        av_log(s, AV_LOG_ERROR, "Unable to find requested track\n");
249
+        return AVERROR_STREAM_NOT_FOUND;
250
+    }
251
+    rtsp_st   = rt->rtsp_streams[streamid];
252
+    localport = rt->rtp_port_min;
253
+
254
+    if (request.transports[0].lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
255
+        rt->lower_transport = RTSP_LOWER_TRANSPORT_TCP;
256
+        if ((ret = ff_rtsp_open_transport_ctx(s, rtsp_st))) {
257
+            rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
258
+            return ret;
259
+        }
260
+        rtsp_st->interleaved_min = request.transports[0].interleaved_min;
261
+        rtsp_st->interleaved_max = request.transports[0].interleaved_max;
262
+        snprintf(responseheaders, sizeof(responseheaders), "Transport: "
263
+                 "RTP/AVP/TCP;unicast;mode=receive;interleaved=%d-%d"
264
+                 "\r\n", request.transports[0].interleaved_min,
265
+                 request.transports[0].interleaved_max);
266
+    } else {
267
+        do {
268
+            ff_url_join(url, sizeof(url), "rtp", NULL, host, localport, NULL);
269
+            av_dlog(s, "Opening: %s", url);
270
+            ret = ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
271
+                             &s->interrupt_callback, NULL);
272
+            if (ret)
273
+                localport += 2;
274
+        } while (ret || localport > rt->rtp_port_max);
275
+        if (localport > rt->rtp_port_max) {
276
+            rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
277
+            return ret;
278
+        }
279
+
280
+        av_dlog(s, "Listening on: %d",
281
+                ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle));
282
+        if ((ret = ff_rtsp_open_transport_ctx(s, rtsp_st))) {
283
+            rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
284
+            return ret;
285
+        }
286
+
287
+        localport = ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle);
288
+        snprintf(responseheaders, sizeof(responseheaders), "Transport: "
289
+                 "RTP/AVP/UDP;unicast;mode=receive;source=%s;"
290
+                 "client_port=%d-%d;server_port=%d-%d\r\n",
291
+                 host, request.transports[0].client_port_min,
292
+                 request.transports[0].client_port_max, localport,
293
+                 localport + 1);
294
+    }
295
+
296
+    /* Establish sessionid if not previously set */
297
+    /* Put this in a function? */
298
+    /* RFC 2326: session id must be at least 8 digits */
299
+    while (strlen(rt->session_id) < 8)
300
+        av_strlcatf(rt->session_id, 512, "%u", av_get_random_seed());
301
+
302
+    av_strlcatf(responseheaders, sizeof(responseheaders), "Session: %s\r\n",
303
+                rt->session_id);
304
+    /* Send Reply */
305
+    rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq);
306
+
307
+    rt->state = RTSP_STATE_PAUSED;
308
+    return 0;
309
+}
310
+
311
+static int rtsp_read_record(AVFormatContext *s)
312
+{
313
+    RTSPState *rt             = s->priv_data;
314
+    RTSPMessageHeader request = { 0 };
315
+    int ret                   = 0;
316
+    char responseheaders[1024];
317
+
318
+    ret = rtsp_read_request(s, &request, "RECORD");
319
+    if (ret)
320
+        return ret;
321
+    ret = check_sessionid(s, &request);
322
+    if (ret)
323
+        return ret;
324
+    rt->seq++;
325
+    snprintf(responseheaders, sizeof(responseheaders), "Session: %s\r\n",
326
+             rt->session_id);
327
+    rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq);
328
+
329
+    rt->state = RTSP_STATE_STREAMING;
330
+    return 0;
331
+}
332
+
333
+static inline int parse_command_line(AVFormatContext *s, const char *line,
334
+                                     int linelen, char *uri, int urisize,
335
+                                     char *method, int methodsize,
336
+                                     enum RTSPMethod *methodcode)
337
+{
338
+    RTSPState *rt = s->priv_data;
339
+    const char *linept, *searchlinept;
340
+    linept = strchr(line, ' ');
341
+    if (linept - line > methodsize - 1) {
342
+        av_log(s, AV_LOG_ERROR, "Method string too long\n");
343
+        return AVERROR(EIO);
344
+    }
345
+    memcpy(method, line, linept - line);
346
+    method[linept - line] = '\0';
347
+    linept++;
348
+    if (!strcmp(method, "ANNOUNCE"))
349
+        *methodcode = ANNOUNCE;
350
+    else if (!strcmp(method, "OPTIONS"))
351
+        *methodcode = OPTIONS;
352
+    else if (!strcmp(method, "RECORD"))
353
+        *methodcode = RECORD;
354
+    else if (!strcmp(method, "SETUP"))
355
+        *methodcode = SETUP;
356
+    else if (!strcmp(method, "PAUSE"))
357
+        *methodcode = PAUSE;
358
+    else if (!strcmp(method, "TEARDOWN"))
359
+        *methodcode = TEARDOWN;
360
+    else
361
+        *methodcode = UNKNOWN;
362
+    /* Check method with the state  */
363
+    if (rt->state == RTSP_STATE_IDLE) {
364
+        if ((*methodcode != ANNOUNCE) && (*methodcode != OPTIONS)) {
365
+            av_log(s, AV_LOG_ERROR, "Unexpected command in Idle State %s\n",
366
+                   line);
367
+            return AVERROR_PROTOCOL_NOT_FOUND;
368
+        }
369
+    } else if (rt->state == RTSP_STATE_PAUSED) {
370
+        if ((*methodcode != OPTIONS) && (*methodcode != RECORD)
371
+            && (*methodcode != SETUP)) {
372
+            av_log(s, AV_LOG_ERROR, "Unexpected command in Paused State %s\n",
373
+                   line);
374
+            return AVERROR_PROTOCOL_NOT_FOUND;
375
+        }
376
+    } else if (rt->state == RTSP_STATE_STREAMING) {
377
+        if ((*methodcode != PAUSE) && (*methodcode != OPTIONS)
378
+            && (*methodcode != TEARDOWN)) {
379
+            av_log(s, AV_LOG_ERROR, "Unexpected command in Streaming State"
380
+                   " %s\n", line);
381
+            return AVERROR_PROTOCOL_NOT_FOUND;
382
+        }
383
+    } else {
384
+        av_log(s, AV_LOG_ERROR, "Unexpected State [%d]\n", rt->state);
385
+        return AVERROR_BUG;
386
+    }
387
+
388
+    searchlinept = strchr(linept, ' ');
389
+    if (searchlinept == NULL) {
390
+        av_log(s, AV_LOG_ERROR, "Error parsing message URI\n");
391
+        return AVERROR_INVALIDDATA;
392
+    }
393
+    if (searchlinept - linept > urisize - 1) {
394
+        av_log(s, AV_LOG_ERROR, "uri string length exceeded buffer size\n");
395
+        return AVERROR(EIO);
396
+    }
397
+    memcpy(uri, linept, searchlinept - linept);
398
+    uri[searchlinept - linept] = '\0';
399
+    if (strcmp(rt->control_uri, uri)) {
400
+        char host[128], path[512], auth[128];
401
+        int port;
402
+        char ctl_host[128], ctl_path[512], ctl_auth[128];
403
+        int ctl_port;
404
+        av_url_split(NULL, 0, auth, sizeof(auth), host, sizeof(host), &port,
405
+                     path, sizeof(path), uri);
406
+        av_url_split(NULL, 0, ctl_auth, sizeof(ctl_auth), ctl_host,
407
+                     sizeof(ctl_host), &ctl_port, ctl_path, sizeof(ctl_path),
408
+                     rt->control_uri);
409
+        if (strcmp(host, ctl_host))
410
+            av_log(s, AV_LOG_INFO, "Host %s differs from expected %s\n",
411
+                   host, ctl_host);
412
+        if (strcmp(path, ctl_path) && *methodcode != SETUP)
413
+            av_log(s, AV_LOG_WARNING, "WARNING: Path %s differs from expected"
414
+                   " %s\n", path, ctl_path);
415
+        if (*methodcode == ANNOUNCE) {
416
+            av_log(s, AV_LOG_INFO,
417
+                   "Updating control URI to %s\n", uri);
418
+            strcpy(rt->control_uri, uri);
419
+        }
420
+    }
421
+
422
+    linept = searchlinept + 1;
423
+    if (!av_strstart(linept, "RTSP/1.0", NULL)) {
424
+        av_log(s, AV_LOG_ERROR, "Error parsing protocol or version\n");
425
+        return AVERROR_PROTOCOL_NOT_FOUND;
426
+    }
427
+    return 0;
428
+}
429
+
430
+int ff_rtsp_parse_streaming_commands(AVFormatContext *s)
431
+{
432
+    RTSPState *rt = s->priv_data;
433
+    unsigned char rbuf[4096];
434
+    unsigned char method[10];
435
+    char uri[500];
436
+    int ret;
437
+    int rbuflen               = 0;
438
+    RTSPMessageHeader request = { 0 };
439
+    enum RTSPMethod methodcode;
440
+
441
+    ret = read_line(s, rbuf, sizeof(rbuf), &rbuflen);
442
+    if (ret < 0)
443
+        return ret;
444
+    ret = parse_command_line(s, rbuf, rbuflen, uri, sizeof(uri), method,
445
+                             sizeof(method), &methodcode);
446
+    if (ret) {
447
+        av_log(s, AV_LOG_ERROR, "RTSP: Unexpected Command\n");
448
+        return ret;
449
+    }
450
+
451
+    ret = rtsp_read_request(s, &request, method);
452
+    if (ret)
453
+        return ret;
454
+    rt->seq++;
455
+    if (methodcode == PAUSE) {
456
+        rt->state = RTSP_STATE_PAUSED;
457
+        ret       = rtsp_send_reply(s, RTSP_STATUS_OK, NULL , request.seq);
458
+        // TODO: Missing date header in response
459
+    } else if (methodcode == OPTIONS) {
460
+        ret = rtsp_send_reply(s, RTSP_STATUS_OK,
461
+                              "Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, "
462
+                              "RECORD\r\n", request.seq);
463
+    } else if (methodcode == TEARDOWN) {
464
+        rt->state = RTSP_STATE_IDLE;
465
+        ret       = rtsp_send_reply(s, RTSP_STATUS_OK, NULL , request.seq);
466
+        return 0;
467
+    }
468
+    return ret;
469
+}
470
+
48 471
 static int rtsp_read_play(AVFormatContext *s)
49 472
 {
50 473
     RTSPState *rt = s->priv_data;
... ...
@@ -157,6 +600,67 @@ int ff_rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply)
157 157
     return 0;
158 158
 }
159 159
 
160
+static int rtsp_listen(AVFormatContext *s)
161
+{
162
+    RTSPState *rt = s->priv_data;
163
+    char host[128], path[512], auth[128];
164
+    char uri[500];
165
+    int port;
166
+    char tcpname[500];
167
+    unsigned char rbuf[4096];
168
+    unsigned char method[10];
169
+    int rbuflen = 0;
170
+    int ret;
171
+    enum RTSPMethod methodcode;
172
+
173
+    /* extract hostname and port */
174
+    av_url_split(NULL, 0, auth, sizeof(auth), host, sizeof(host), &port,
175
+                 path, sizeof(path), s->filename);
176
+
177
+    /* ff_url_join. No authorization by now (NULL) */
178
+    ff_url_join(rt->control_uri, sizeof(rt->control_uri), "rtsp", NULL, host,
179
+                port, "%s", path);
180
+    /* Create TCP connection */
181
+    ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port,
182
+                "?listen&listen_timeout=%d", rt->initial_timeout * 1000);
183
+
184
+    if (ret = ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,
185
+                         &s->interrupt_callback, NULL)) {
186
+        av_log(s, AV_LOG_ERROR, "Unable to open RTSP for listening\n");
187
+        return ret;
188
+    }
189
+    rt->state       = RTSP_STATE_IDLE;
190
+    rt->rtsp_hd_out = rt->rtsp_hd;
191
+    for (;;) { /* Wait for incoming RTSP messages */
192
+        ret = read_line(s, rbuf, sizeof(rbuf), &rbuflen);
193
+        if (ret < 0)
194
+            return ret;
195
+        ret = parse_command_line(s, rbuf, rbuflen, uri, sizeof(uri), method,
196
+                                 sizeof(method), &methodcode);
197
+        if (ret) {
198
+            av_log(s, AV_LOG_ERROR, "RTSP: Unexpected Command\n");
199
+            return ret;
200
+        }
201
+
202
+        if (methodcode == ANNOUNCE) {
203
+            ret       = rtsp_read_announce(s);
204
+            rt->state = RTSP_STATE_PAUSED;
205
+        } else if (methodcode == OPTIONS) {
206
+            ret = rtsp_read_options(s);
207
+        } else if (methodcode == RECORD) {
208
+            ret = rtsp_read_record(s);
209
+            if (!ret)
210
+                return 0; // We are ready for streaming
211
+        } else if (methodcode == SETUP)
212
+            ret = rtsp_read_setup(s, host, uri);
213
+        if (ret) {
214
+            ffurl_close(rt->rtsp_hd);
215
+            return AVERROR_INVALIDDATA;
216
+        }
217
+    }
218
+    return 0;
219
+}
220
+
160 221
 static int rtsp_probe(AVProbeData *p)
161 222
 {
162 223
     if (av_strstart(p->filename, "rtsp:", NULL))
... ...
@@ -169,23 +673,32 @@ static int rtsp_read_header(AVFormatContext *s)
169 169
     RTSPState *rt = s->priv_data;
170 170
     int ret;
171 171
 
172
-    ret = ff_rtsp_connect(s);
173
-    if (ret)
174
-        return ret;
175
-
176
-    rt->real_setup_cache = !s->nb_streams ? NULL :
177
-                           av_mallocz(2 * s->nb_streams * sizeof(*rt->real_setup_cache));
178
-    if (!rt->real_setup_cache && s->nb_streams)
179
-        return AVERROR(ENOMEM);
180
-    rt->real_setup = rt->real_setup_cache + s->nb_streams;
172
+    if (rt->initial_timeout > 0)
173
+        rt->rtsp_flags |= RTSP_FLAG_LISTEN;
181 174
 
182
-    if (rt->initial_pause) {
183
-         /* do not start immediately */
175
+    if (rt->rtsp_flags & RTSP_FLAG_LISTEN) {
176
+        ret = rtsp_listen(s);
177
+        if (ret)
178
+            return ret;
184 179
     } else {
185
-         if (rtsp_read_play(s) < 0) {
186
-            ff_rtsp_close_streams(s);
187
-            ff_rtsp_close_connections(s);
188
-            return AVERROR_INVALIDDATA;
180
+        ret = ff_rtsp_connect(s);
181
+        if (ret)
182
+            return ret;
183
+
184
+        rt->real_setup_cache = !s->nb_streams ? NULL :
185
+            av_mallocz(2 * s->nb_streams * sizeof(*rt->real_setup_cache));
186
+        if (!rt->real_setup_cache && s->nb_streams)
187
+            return AVERROR(ENOMEM);
188
+        rt->real_setup = rt->real_setup_cache + s->nb_streams;
189
+
190
+        if (rt->initial_pause) {
191
+            /* do not start immediately */
192
+        } else {
193
+            if (rtsp_read_play(s) < 0) {
194
+                ff_rtsp_close_streams(s);
195
+                ff_rtsp_close_connections(s);
196
+                return AVERROR_INVALIDDATA;
197
+            }
189 198
         }
190 199
     }
191 200
 
... ...
@@ -349,20 +862,22 @@ retry:
349 349
     }
350 350
     rt->packets++;
351 351
 
352
-    /* send dummy request to keep TCP connection alive */
353
-    if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2 ||
354
-         rt->auth_state.stale) {
355
-        if (rt->server_type == RTSP_SERVER_WMS ||
356
-           (rt->server_type != RTSP_SERVER_REAL &&
357
-            rt->get_parameter_supported)) {
358
-            ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL);
359
-        } else {
360
-            ff_rtsp_send_cmd_async(s, "OPTIONS", "*", NULL);
352
+    if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN)) {
353
+        /* send dummy request to keep TCP connection alive */
354
+        if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2 ||
355
+            rt->auth_state.stale) {
356
+            if (rt->server_type == RTSP_SERVER_WMS ||
357
+                (rt->server_type != RTSP_SERVER_REAL &&
358
+                 rt->get_parameter_supported)) {
359
+                ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL);
360
+            } else {
361
+                ff_rtsp_send_cmd_async(s, "OPTIONS", "*", NULL);
362
+            }
363
+            /* The stale flag should be reset when creating the auth response in
364
+             * ff_rtsp_send_cmd_async, but reset it here just in case we never
365
+             * called the auth code (if we didn't have any credentials set). */
366
+            rt->auth_state.stale = 0;
361 367
         }
362
-        /* The stale flag should be reset when creating the auth response in
363
-         * ff_rtsp_send_cmd_async, but reset it here just in case we never
364
-         * called the auth code (if we didn't have any credentials set). */
365
-        rt->auth_state.stale = 0;
366 368
     }
367 369
 
368 370
     return 0;
... ...
@@ -30,7 +30,7 @@
30 30
 #include "libavutil/avutil.h"
31 31
 
32 32
 #define LIBAVFORMAT_VERSION_MAJOR 54
33
-#define LIBAVFORMAT_VERSION_MINOR  6
33
+#define LIBAVFORMAT_VERSION_MINOR  7
34 34
 #define LIBAVFORMAT_VERSION_MICRO  0
35 35
 
36 36
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \