~ubuntu-branches/ubuntu/saucy/gst-libav1.0/saucy-proposed

« back to all changes in this revision

Viewing changes to gst-libs/ext/libav/libavformat/rtspdec.c

  • Committer: Package Import Robot
  • Author(s): Sebastian Dröge
  • Date: 2013-07-30 09:00:15 UTC
  • mfrom: (1.1.16) (7.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20130730090015-sc1ou2yssu7q5w4e
Tags: 1.1.3-1
* New upstream development snapshot:
  + debian/control:
    - Build depend on GStreamer and gst-plugins-base >= 1.1.3.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
#include "libavutil/avstring.h"
23
23
#include "libavutil/intreadwrite.h"
24
24
#include "libavutil/mathematics.h"
 
25
#include "libavutil/random_seed.h"
 
26
#include "libavutil/time.h"
25
27
#include "avformat.h"
26
28
 
27
29
#include "internal.h"
31
33
#include "rdt.h"
32
34
#include "url.h"
33
35
 
 
36
static const struct RTSPStatusMessage {
 
37
    enum RTSPStatusCode code;
 
38
    const char *message;
 
39
} status_messages[] = {
 
40
    { RTSP_STATUS_OK,             "OK"                               },
 
41
    { RTSP_STATUS_METHOD,         "Method Not Allowed"               },
 
42
    { RTSP_STATUS_BANDWIDTH,      "Not Enough Bandwidth"             },
 
43
    { RTSP_STATUS_SESSION,        "Session Not Found"                },
 
44
    { RTSP_STATUS_STATE,          "Method Not Valid in This State"   },
 
45
    { RTSP_STATUS_AGGREGATE,      "Aggregate operation not allowed"  },
 
46
    { RTSP_STATUS_ONLY_AGGREGATE, "Only aggregate operation allowed" },
 
47
    { RTSP_STATUS_TRANSPORT,      "Unsupported transport"            },
 
48
    { RTSP_STATUS_INTERNAL,       "Internal Server Error"            },
 
49
    { RTSP_STATUS_SERVICE,        "Service Unavailable"              },
 
50
    { RTSP_STATUS_VERSION,        "RTSP Version not supported"       },
 
51
    { 0,                          "NULL"                             }
 
52
};
 
53
 
 
54
static int rtsp_read_close(AVFormatContext *s)
 
55
{
 
56
    RTSPState *rt = s->priv_data;
 
57
 
 
58
    if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN))
 
59
        ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
 
60
 
 
61
    ff_rtsp_close_streams(s);
 
62
    ff_rtsp_close_connections(s);
 
63
    ff_network_close();
 
64
    rt->real_setup = NULL;
 
65
    av_freep(&rt->real_setup_cache);
 
66
    return 0;
 
67
}
 
68
 
 
69
static inline int read_line(AVFormatContext *s, char *rbuf, const int rbufsize,
 
70
                            int *rbuflen)
 
71
{
 
72
    RTSPState *rt = s->priv_data;
 
73
    int idx       = 0;
 
74
    int ret       = 0;
 
75
    *rbuflen      = 0;
 
76
 
 
77
    do {
 
78
        ret = ffurl_read_complete(rt->rtsp_hd, rbuf + idx, 1);
 
79
        if (ret <= 0)
 
80
            return ret ? ret : AVERROR_EOF;
 
81
        if (rbuf[idx] == '\r') {
 
82
            /* Ignore */
 
83
        } else if (rbuf[idx] == '\n') {
 
84
            rbuf[idx] = '\0';
 
85
            *rbuflen  = idx;
 
86
            return 0;
 
87
        } else
 
88
            idx++;
 
89
    } while (idx < rbufsize);
 
90
    av_log(s, AV_LOG_ERROR, "Message too long\n");
 
91
    return AVERROR(EIO);
 
92
}
 
93
 
 
94
static int rtsp_send_reply(AVFormatContext *s, enum RTSPStatusCode code,
 
95
                           const char *extracontent, uint16_t seq)
 
96
{
 
97
    RTSPState *rt = s->priv_data;
 
98
    char message[4096];
 
99
    int index = 0;
 
100
    while (status_messages[index].code) {
 
101
        if (status_messages[index].code == code) {
 
102
            snprintf(message, sizeof(message), "RTSP/1.0 %d %s\r\n",
 
103
                     code, status_messages[index].message);
 
104
            break;
 
105
        }
 
106
        index++;
 
107
    }
 
108
    if (!status_messages[index].code)
 
109
        return AVERROR(EINVAL);
 
110
    av_strlcatf(message, sizeof(message), "CSeq: %d\r\n", seq);
 
111
    av_strlcatf(message, sizeof(message), "Server: %s\r\n", LIBAVFORMAT_IDENT);
 
112
    if (extracontent)
 
113
        av_strlcat(message, extracontent, sizeof(message));
 
114
    av_strlcat(message, "\r\n", sizeof(message));
 
115
    av_dlog(s, "Sending response:\n%s", message);
 
116
    ffurl_write(rt->rtsp_hd, message, strlen(message));
 
117
 
 
118
    return 0;
 
119
}
 
120
 
 
121
static inline int check_sessionid(AVFormatContext *s,
 
122
                                  RTSPMessageHeader *request)
 
123
{
 
124
    RTSPState *rt = s->priv_data;
 
125
    unsigned char *session_id = rt->session_id;
 
126
    if (!session_id[0]) {
 
127
        av_log(s, AV_LOG_WARNING, "There is no session-id at the moment\n");
 
128
        return 0;
 
129
    }
 
130
    if (strcmp(session_id, request->session_id)) {
 
131
        av_log(s, AV_LOG_ERROR, "Unexpected session-id %s\n",
 
132
               request->session_id);
 
133
        rtsp_send_reply(s, RTSP_STATUS_SESSION, NULL, request->seq);
 
134
        return AVERROR_STREAM_NOT_FOUND;
 
135
    }
 
136
    return 0;
 
137
}
 
138
 
 
139
static inline int rtsp_read_request(AVFormatContext *s,
 
140
                                    RTSPMessageHeader *request,
 
141
                                    const char *method)
 
142
{
 
143
    RTSPState *rt = s->priv_data;
 
144
    char rbuf[1024];
 
145
    int rbuflen, ret;
 
146
    do {
 
147
        ret = read_line(s, rbuf, sizeof(rbuf), &rbuflen);
 
148
        if (ret)
 
149
            return ret;
 
150
        if (rbuflen > 1) {
 
151
            av_dlog(s, "Parsing[%d]: %s\n", rbuflen, rbuf);
 
152
            ff_rtsp_parse_line(request, rbuf, rt, method);
 
153
        }
 
154
    } while (rbuflen > 0);
 
155
    if (request->seq != rt->seq + 1) {
 
156
        av_log(s, AV_LOG_ERROR, "Unexpected Sequence number %d\n",
 
157
               request->seq);
 
158
        return AVERROR(EINVAL);
 
159
    }
 
160
    if (rt->session_id[0] && strcmp(method, "OPTIONS")) {
 
161
        ret = check_sessionid(s, request);
 
162
        if (ret)
 
163
            return ret;
 
164
    }
 
165
 
 
166
    return 0;
 
167
}
 
168
 
 
169
static int rtsp_read_announce(AVFormatContext *s)
 
170
{
 
171
    RTSPState *rt             = s->priv_data;
 
172
    RTSPMessageHeader request = { 0 };
 
173
    char sdp[4096];
 
174
    int  ret;
 
175
 
 
176
    ret = rtsp_read_request(s, &request, "ANNOUNCE");
 
177
    if (ret)
 
178
        return ret;
 
179
    rt->seq++;
 
180
    if (strcmp(request.content_type, "application/sdp")) {
 
181
        av_log(s, AV_LOG_ERROR, "Unexpected content type %s\n",
 
182
               request.content_type);
 
183
        rtsp_send_reply(s, RTSP_STATUS_SERVICE, NULL, request.seq);
 
184
        return AVERROR_OPTION_NOT_FOUND;
 
185
    }
 
186
    if (request.content_length && request.content_length < sizeof(sdp) - 1) {
 
187
        /* Read SDP */
 
188
        if (ffurl_read_complete(rt->rtsp_hd, sdp, request.content_length)
 
189
            < request.content_length) {
 
190
            av_log(s, AV_LOG_ERROR,
 
191
                   "Unable to get complete SDP Description in ANNOUNCE\n");
 
192
            rtsp_send_reply(s, RTSP_STATUS_INTERNAL, NULL, request.seq);
 
193
            return AVERROR(EIO);
 
194
        }
 
195
        sdp[request.content_length] = '\0';
 
196
        av_log(s, AV_LOG_VERBOSE, "SDP: %s\n", sdp);
 
197
        ret = ff_sdp_parse(s, sdp);
 
198
        if (ret)
 
199
            return ret;
 
200
        rtsp_send_reply(s, RTSP_STATUS_OK, NULL, request.seq);
 
201
        return 0;
 
202
    }
 
203
    av_log(s, AV_LOG_ERROR,
 
204
           "Content-Length header value exceeds sdp allocated buffer (4KB)\n");
 
205
    rtsp_send_reply(s, RTSP_STATUS_INTERNAL,
 
206
                    "Content-Length exceeds buffer size", request.seq);
 
207
    return AVERROR(EIO);
 
208
}
 
209
 
 
210
static int rtsp_read_options(AVFormatContext *s)
 
211
{
 
212
    RTSPState *rt             = s->priv_data;
 
213
    RTSPMessageHeader request = { 0 };
 
214
    int ret                   = 0;
 
215
 
 
216
    /* Parsing headers */
 
217
    ret = rtsp_read_request(s, &request, "OPTIONS");
 
218
    if (ret)
 
219
        return ret;
 
220
    rt->seq++;
 
221
    /* Send Reply */
 
222
    rtsp_send_reply(s, RTSP_STATUS_OK,
 
223
                    "Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, RECORD\r\n",
 
224
                    request.seq);
 
225
    return 0;
 
226
}
 
227
 
 
228
static int rtsp_read_setup(AVFormatContext *s, char* host, char *controlurl)
 
229
{
 
230
    RTSPState *rt             = s->priv_data;
 
231
    RTSPMessageHeader request = { 0 };
 
232
    int ret                   = 0;
 
233
    char url[1024];
 
234
    RTSPStream *rtsp_st;
 
235
    char responseheaders[1024];
 
236
    int localport    = -1;
 
237
    int transportidx = 0;
 
238
    int streamid     = 0;
 
239
 
 
240
    ret = rtsp_read_request(s, &request, "SETUP");
 
241
    if (ret)
 
242
        return ret;
 
243
    rt->seq++;
 
244
    if (!request.nb_transports) {
 
245
        av_log(s, AV_LOG_ERROR, "No transport defined in SETUP\n");
 
246
        return AVERROR_INVALIDDATA;
 
247
    }
 
248
    for (transportidx = 0; transportidx < request.nb_transports;
 
249
         transportidx++) {
 
250
        if (!request.transports[transportidx].mode_record ||
 
251
            (request.transports[transportidx].lower_transport !=
 
252
             RTSP_LOWER_TRANSPORT_UDP &&
 
253
             request.transports[transportidx].lower_transport !=
 
254
             RTSP_LOWER_TRANSPORT_TCP)) {
 
255
            av_log(s, AV_LOG_ERROR, "mode=record/receive not set or transport"
 
256
                   " protocol not supported (yet)\n");
 
257
            return AVERROR_INVALIDDATA;
 
258
        }
 
259
    }
 
260
    if (request.nb_transports > 1)
 
261
        av_log(s, AV_LOG_WARNING, "More than one transport not supported, "
 
262
               "using first of all\n");
 
263
    for (streamid = 0; streamid < rt->nb_rtsp_streams; streamid++) {
 
264
        if (!strcmp(rt->rtsp_streams[streamid]->control_url,
 
265
                    controlurl))
 
266
            break;
 
267
    }
 
268
    if (streamid == rt->nb_rtsp_streams) {
 
269
        av_log(s, AV_LOG_ERROR, "Unable to find requested track\n");
 
270
        return AVERROR_STREAM_NOT_FOUND;
 
271
    }
 
272
    rtsp_st   = rt->rtsp_streams[streamid];
 
273
    localport = rt->rtp_port_min;
 
274
 
 
275
    if (request.transports[0].lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
 
276
        rt->lower_transport = RTSP_LOWER_TRANSPORT_TCP;
 
277
        if ((ret = ff_rtsp_open_transport_ctx(s, rtsp_st))) {
 
278
            rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
 
279
            return ret;
 
280
        }
 
281
        rtsp_st->interleaved_min = request.transports[0].interleaved_min;
 
282
        rtsp_st->interleaved_max = request.transports[0].interleaved_max;
 
283
        snprintf(responseheaders, sizeof(responseheaders), "Transport: "
 
284
                 "RTP/AVP/TCP;unicast;mode=receive;interleaved=%d-%d"
 
285
                 "\r\n", request.transports[0].interleaved_min,
 
286
                 request.transports[0].interleaved_max);
 
287
    } else {
 
288
        do {
 
289
            ff_url_join(url, sizeof(url), "rtp", NULL, host, localport, NULL);
 
290
            av_dlog(s, "Opening: %s", url);
 
291
            ret = ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
 
292
                             &s->interrupt_callback, NULL);
 
293
            if (ret)
 
294
                localport += 2;
 
295
        } while (ret || localport > rt->rtp_port_max);
 
296
        if (localport > rt->rtp_port_max) {
 
297
            rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
 
298
            return ret;
 
299
        }
 
300
 
 
301
        av_dlog(s, "Listening on: %d",
 
302
                ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle));
 
303
        if ((ret = ff_rtsp_open_transport_ctx(s, rtsp_st))) {
 
304
            rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
 
305
            return ret;
 
306
        }
 
307
 
 
308
        localport = ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle);
 
309
        snprintf(responseheaders, sizeof(responseheaders), "Transport: "
 
310
                 "RTP/AVP/UDP;unicast;mode=receive;source=%s;"
 
311
                 "client_port=%d-%d;server_port=%d-%d\r\n",
 
312
                 host, request.transports[0].client_port_min,
 
313
                 request.transports[0].client_port_max, localport,
 
314
                 localport + 1);
 
315
    }
 
316
 
 
317
    /* Establish sessionid if not previously set */
 
318
    /* Put this in a function? */
 
319
    /* RFC 2326: session id must be at least 8 digits */
 
320
    while (strlen(rt->session_id) < 8)
 
321
        av_strlcatf(rt->session_id, 512, "%u", av_get_random_seed());
 
322
 
 
323
    av_strlcatf(responseheaders, sizeof(responseheaders), "Session: %s\r\n",
 
324
                rt->session_id);
 
325
    /* Send Reply */
 
326
    rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq);
 
327
 
 
328
    rt->state = RTSP_STATE_PAUSED;
 
329
    return 0;
 
330
}
 
331
 
 
332
static int rtsp_read_record(AVFormatContext *s)
 
333
{
 
334
    RTSPState *rt             = s->priv_data;
 
335
    RTSPMessageHeader request = { 0 };
 
336
    int ret                   = 0;
 
337
    char responseheaders[1024];
 
338
 
 
339
    ret = rtsp_read_request(s, &request, "RECORD");
 
340
    if (ret)
 
341
        return ret;
 
342
    ret = check_sessionid(s, &request);
 
343
    if (ret)
 
344
        return ret;
 
345
    rt->seq++;
 
346
    snprintf(responseheaders, sizeof(responseheaders), "Session: %s\r\n",
 
347
             rt->session_id);
 
348
    rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq);
 
349
 
 
350
    rt->state = RTSP_STATE_STREAMING;
 
351
    return 0;
 
352
}
 
353
 
 
354
static inline int parse_command_line(AVFormatContext *s, const char *line,
 
355
                                     int linelen, char *uri, int urisize,
 
356
                                     char *method, int methodsize,
 
357
                                     enum RTSPMethod *methodcode)
 
358
{
 
359
    RTSPState *rt = s->priv_data;
 
360
    const char *linept, *searchlinept;
 
361
    linept = strchr(line, ' ');
 
362
    if (linept - line > methodsize - 1) {
 
363
        av_log(s, AV_LOG_ERROR, "Method string too long\n");
 
364
        return AVERROR(EIO);
 
365
    }
 
366
    memcpy(method, line, linept - line);
 
367
    method[linept - line] = '\0';
 
368
    linept++;
 
369
    if (!strcmp(method, "ANNOUNCE"))
 
370
        *methodcode = ANNOUNCE;
 
371
    else if (!strcmp(method, "OPTIONS"))
 
372
        *methodcode = OPTIONS;
 
373
    else if (!strcmp(method, "RECORD"))
 
374
        *methodcode = RECORD;
 
375
    else if (!strcmp(method, "SETUP"))
 
376
        *methodcode = SETUP;
 
377
    else if (!strcmp(method, "PAUSE"))
 
378
        *methodcode = PAUSE;
 
379
    else if (!strcmp(method, "TEARDOWN"))
 
380
        *methodcode = TEARDOWN;
 
381
    else
 
382
        *methodcode = UNKNOWN;
 
383
    /* Check method with the state  */
 
384
    if (rt->state == RTSP_STATE_IDLE) {
 
385
        if ((*methodcode != ANNOUNCE) && (*methodcode != OPTIONS)) {
 
386
            av_log(s, AV_LOG_ERROR, "Unexpected command in Idle State %s\n",
 
387
                   line);
 
388
            return AVERROR_PROTOCOL_NOT_FOUND;
 
389
        }
 
390
    } else if (rt->state == RTSP_STATE_PAUSED) {
 
391
        if ((*methodcode != OPTIONS) && (*methodcode != RECORD)
 
392
            && (*methodcode != SETUP)) {
 
393
            av_log(s, AV_LOG_ERROR, "Unexpected command in Paused State %s\n",
 
394
                   line);
 
395
            return AVERROR_PROTOCOL_NOT_FOUND;
 
396
        }
 
397
    } else if (rt->state == RTSP_STATE_STREAMING) {
 
398
        if ((*methodcode != PAUSE) && (*methodcode != OPTIONS)
 
399
            && (*methodcode != TEARDOWN)) {
 
400
            av_log(s, AV_LOG_ERROR, "Unexpected command in Streaming State"
 
401
                   " %s\n", line);
 
402
            return AVERROR_PROTOCOL_NOT_FOUND;
 
403
        }
 
404
    } else {
 
405
        av_log(s, AV_LOG_ERROR, "Unexpected State [%d]\n", rt->state);
 
406
        return AVERROR_BUG;
 
407
    }
 
408
 
 
409
    searchlinept = strchr(linept, ' ');
 
410
    if (searchlinept == NULL) {
 
411
        av_log(s, AV_LOG_ERROR, "Error parsing message URI\n");
 
412
        return AVERROR_INVALIDDATA;
 
413
    }
 
414
    if (searchlinept - linept > urisize - 1) {
 
415
        av_log(s, AV_LOG_ERROR, "uri string length exceeded buffer size\n");
 
416
        return AVERROR(EIO);
 
417
    }
 
418
    memcpy(uri, linept, searchlinept - linept);
 
419
    uri[searchlinept - linept] = '\0';
 
420
    if (strcmp(rt->control_uri, uri)) {
 
421
        char host[128], path[512], auth[128];
 
422
        int port;
 
423
        char ctl_host[128], ctl_path[512], ctl_auth[128];
 
424
        int ctl_port;
 
425
        av_url_split(NULL, 0, auth, sizeof(auth), host, sizeof(host), &port,
 
426
                     path, sizeof(path), uri);
 
427
        av_url_split(NULL, 0, ctl_auth, sizeof(ctl_auth), ctl_host,
 
428
                     sizeof(ctl_host), &ctl_port, ctl_path, sizeof(ctl_path),
 
429
                     rt->control_uri);
 
430
        if (strcmp(host, ctl_host))
 
431
            av_log(s, AV_LOG_INFO, "Host %s differs from expected %s\n",
 
432
                   host, ctl_host);
 
433
        if (strcmp(path, ctl_path) && *methodcode != SETUP)
 
434
            av_log(s, AV_LOG_WARNING, "WARNING: Path %s differs from expected"
 
435
                   " %s\n", path, ctl_path);
 
436
        if (*methodcode == ANNOUNCE) {
 
437
            av_log(s, AV_LOG_INFO,
 
438
                   "Updating control URI to %s\n", uri);
 
439
            av_strlcpy(rt->control_uri, uri, sizeof(rt->control_uri));
 
440
        }
 
441
    }
 
442
 
 
443
    linept = searchlinept + 1;
 
444
    if (!av_strstart(linept, "RTSP/1.0", NULL)) {
 
445
        av_log(s, AV_LOG_ERROR, "Error parsing protocol or version\n");
 
446
        return AVERROR_PROTOCOL_NOT_FOUND;
 
447
    }
 
448
    return 0;
 
449
}
 
450
 
 
451
int ff_rtsp_parse_streaming_commands(AVFormatContext *s)
 
452
{
 
453
    RTSPState *rt = s->priv_data;
 
454
    unsigned char rbuf[4096];
 
455
    unsigned char method[10];
 
456
    char uri[500];
 
457
    int ret;
 
458
    int rbuflen               = 0;
 
459
    RTSPMessageHeader request = { 0 };
 
460
    enum RTSPMethod methodcode;
 
461
 
 
462
    ret = read_line(s, rbuf, sizeof(rbuf), &rbuflen);
 
463
    if (ret < 0)
 
464
        return ret;
 
465
    ret = parse_command_line(s, rbuf, rbuflen, uri, sizeof(uri), method,
 
466
                             sizeof(method), &methodcode);
 
467
    if (ret) {
 
468
        av_log(s, AV_LOG_ERROR, "RTSP: Unexpected Command\n");
 
469
        return ret;
 
470
    }
 
471
 
 
472
    ret = rtsp_read_request(s, &request, method);
 
473
    if (ret)
 
474
        return ret;
 
475
    rt->seq++;
 
476
    if (methodcode == PAUSE) {
 
477
        rt->state = RTSP_STATE_PAUSED;
 
478
        ret       = rtsp_send_reply(s, RTSP_STATUS_OK, NULL , request.seq);
 
479
        // TODO: Missing date header in response
 
480
    } else if (methodcode == OPTIONS) {
 
481
        ret = rtsp_send_reply(s, RTSP_STATUS_OK,
 
482
                              "Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, "
 
483
                              "RECORD\r\n", request.seq);
 
484
    } else if (methodcode == TEARDOWN) {
 
485
        rt->state = RTSP_STATE_IDLE;
 
486
        ret       = rtsp_send_reply(s, RTSP_STATUS_OK, NULL , request.seq);
 
487
        return 0;
 
488
    }
 
489
    return ret;
 
490
}
 
491
 
34
492
static int rtsp_read_play(AVFormatContext *s)
35
493
{
36
494
    RTSPState *rt = s->priv_data;
143
601
    return 0;
144
602
}
145
603
 
 
604
static int rtsp_listen(AVFormatContext *s)
 
605
{
 
606
    RTSPState *rt = s->priv_data;
 
607
    char host[128], path[512], auth[128];
 
608
    char uri[500];
 
609
    int port;
 
610
    char tcpname[500];
 
611
    unsigned char rbuf[4096];
 
612
    unsigned char method[10];
 
613
    int rbuflen = 0;
 
614
    int ret;
 
615
    enum RTSPMethod methodcode;
 
616
 
 
617
    /* extract hostname and port */
 
618
    av_url_split(NULL, 0, auth, sizeof(auth), host, sizeof(host), &port,
 
619
                 path, sizeof(path), s->filename);
 
620
 
 
621
    /* ff_url_join. No authorization by now (NULL) */
 
622
    ff_url_join(rt->control_uri, sizeof(rt->control_uri), "rtsp", NULL, host,
 
623
                port, "%s", path);
 
624
 
 
625
    if (port < 0)
 
626
        port = RTSP_DEFAULT_PORT;
 
627
 
 
628
    /* Create TCP connection */
 
629
    ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port,
 
630
                "?listen&listen_timeout=%d", rt->initial_timeout * 1000);
 
631
 
 
632
    if (ret = ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,
 
633
                         &s->interrupt_callback, NULL)) {
 
634
        av_log(s, AV_LOG_ERROR, "Unable to open RTSP for listening\n");
 
635
        return ret;
 
636
    }
 
637
    rt->state       = RTSP_STATE_IDLE;
 
638
    rt->rtsp_hd_out = rt->rtsp_hd;
 
639
    for (;;) { /* Wait for incoming RTSP messages */
 
640
        ret = read_line(s, rbuf, sizeof(rbuf), &rbuflen);
 
641
        if (ret < 0)
 
642
            return ret;
 
643
        ret = parse_command_line(s, rbuf, rbuflen, uri, sizeof(uri), method,
 
644
                                 sizeof(method), &methodcode);
 
645
        if (ret) {
 
646
            av_log(s, AV_LOG_ERROR, "RTSP: Unexpected Command\n");
 
647
            return ret;
 
648
        }
 
649
 
 
650
        if (methodcode == ANNOUNCE) {
 
651
            ret       = rtsp_read_announce(s);
 
652
            rt->state = RTSP_STATE_PAUSED;
 
653
        } else if (methodcode == OPTIONS) {
 
654
            ret = rtsp_read_options(s);
 
655
        } else if (methodcode == RECORD) {
 
656
            ret = rtsp_read_record(s);
 
657
            if (!ret)
 
658
                return 0; // We are ready for streaming
 
659
        } else if (methodcode == SETUP)
 
660
            ret = rtsp_read_setup(s, host, uri);
 
661
        if (ret) {
 
662
            ffurl_close(rt->rtsp_hd);
 
663
            return AVERROR_INVALIDDATA;
 
664
        }
 
665
    }
 
666
    return 0;
 
667
}
 
668
 
146
669
static int rtsp_probe(AVProbeData *p)
147
670
{
148
671
    if (av_strstart(p->filename, "rtsp:", NULL))
150
673
    return 0;
151
674
}
152
675
 
153
 
static int rtsp_read_header(AVFormatContext *s,
154
 
                            AVFormatParameters *ap)
 
676
static int rtsp_read_header(AVFormatContext *s)
155
677
{
156
678
    RTSPState *rt = s->priv_data;
157
679
    int ret;
158
680
 
159
 
    ret = ff_rtsp_connect(s);
160
 
    if (ret)
161
 
        return ret;
162
 
 
163
 
    rt->real_setup_cache = av_mallocz(2 * s->nb_streams * sizeof(*rt->real_setup_cache));
164
 
    if (!rt->real_setup_cache)
165
 
        return AVERROR(ENOMEM);
166
 
    rt->real_setup = rt->real_setup_cache + s->nb_streams;
167
 
 
168
 
    if (rt->initial_pause) {
169
 
         /* do not start immediately */
 
681
    if (rt->initial_timeout > 0)
 
682
        rt->rtsp_flags |= RTSP_FLAG_LISTEN;
 
683
 
 
684
    if (rt->rtsp_flags & RTSP_FLAG_LISTEN) {
 
685
        ret = rtsp_listen(s);
 
686
        if (ret)
 
687
            return ret;
170
688
    } else {
171
 
         if (rtsp_read_play(s) < 0) {
172
 
            ff_rtsp_close_streams(s);
173
 
            ff_rtsp_close_connections(s);
174
 
            return AVERROR_INVALIDDATA;
 
689
        ret = ff_rtsp_connect(s);
 
690
        if (ret)
 
691
            return ret;
 
692
 
 
693
        rt->real_setup_cache = !s->nb_streams ? NULL :
 
694
            av_mallocz(2 * s->nb_streams * sizeof(*rt->real_setup_cache));
 
695
        if (!rt->real_setup_cache && s->nb_streams)
 
696
            return AVERROR(ENOMEM);
 
697
        rt->real_setup = rt->real_setup_cache + s->nb_streams;
 
698
 
 
699
        if (rt->initial_pause) {
 
700
            /* do not start immediately */
 
701
        } else {
 
702
            if (rtsp_read_play(s) < 0) {
 
703
                ff_rtsp_close_streams(s);
 
704
                ff_rtsp_close_connections(s);
 
705
                return AVERROR_INVALIDDATA;
 
706
            }
175
707
        }
176
708
    }
177
709
 
335
867
    }
336
868
    rt->packets++;
337
869
 
338
 
    /* send dummy request to keep TCP connection alive */
339
 
    if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2) {
340
 
        if (rt->server_type == RTSP_SERVER_WMS ||
341
 
           (rt->server_type != RTSP_SERVER_REAL &&
342
 
            rt->get_parameter_supported)) {
343
 
            ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL);
344
 
        } else {
345
 
            ff_rtsp_send_cmd_async(s, "OPTIONS", "*", NULL);
 
870
    if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN)) {
 
871
        /* send dummy request to keep TCP connection alive */
 
872
        if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2 ||
 
873
            rt->auth_state.stale) {
 
874
            if (rt->server_type == RTSP_SERVER_WMS ||
 
875
                (rt->server_type != RTSP_SERVER_REAL &&
 
876
                 rt->get_parameter_supported)) {
 
877
                ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL);
 
878
            } else {
 
879
                ff_rtsp_send_cmd_async(s, "OPTIONS", "*", NULL);
 
880
            }
 
881
            /* The stale flag should be reset when creating the auth response in
 
882
             * ff_rtsp_send_cmd_async, but reset it here just in case we never
 
883
             * called the auth code (if we didn't have any credentials set). */
 
884
            rt->auth_state.stale = 0;
346
885
        }
347
886
    }
348
887
 
375
914
    return 0;
376
915
}
377
916
 
378
 
static int rtsp_read_close(AVFormatContext *s)
379
 
{
380
 
    RTSPState *rt = s->priv_data;
381
 
 
382
 
    ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
383
 
 
384
 
    ff_rtsp_close_streams(s);
385
 
    ff_rtsp_close_connections(s);
386
 
    ff_network_close();
387
 
    rt->real_setup = NULL;
388
 
    av_freep(&rt->real_setup_cache);
389
 
    return 0;
390
 
}
391
 
 
392
 
const AVClass rtsp_demuxer_class = {
 
917
static const AVClass rtsp_demuxer_class = {
393
918
    .class_name     = "RTSP demuxer",
394
919
    .item_name      = av_default_item_name,
395
920
    .option         = ff_rtsp_options,
398
923
 
399
924
AVInputFormat ff_rtsp_demuxer = {
400
925
    .name           = "rtsp",
401
 
    .long_name      = NULL_IF_CONFIG_SMALL("RTSP input format"),
 
926
    .long_name      = NULL_IF_CONFIG_SMALL("RTSP input"),
402
927
    .priv_data_size = sizeof(RTSPState),
403
928
    .read_probe     = rtsp_probe,
404
929
    .read_header    = rtsp_read_header,
405
930
    .read_packet    = rtsp_read_packet,
406
931
    .read_close     = rtsp_read_close,
407
932
    .read_seek      = rtsp_read_seek,
408
 
    .flags = AVFMT_NOFILE,
409
 
    .read_play = rtsp_read_play,
410
 
    .read_pause = rtsp_read_pause,
411
 
    .priv_class = &rtsp_demuxer_class,
 
933
    .flags          = AVFMT_NOFILE,
 
934
    .read_play      = rtsp_read_play,
 
935
    .read_pause     = rtsp_read_pause,
 
936
    .priv_class     = &rtsp_demuxer_class,
412
937
};