Coverage Report

Created: 2026-07-25 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavformat/rtspdec.c
Line
Count
Source
1
/*
2
 * RTSP demuxer
3
 * Copyright (c) 2002 Fabrice Bellard
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
#include "config_components.h"
23
24
#include "libavutil/avstring.h"
25
#include "libavutil/avassert.h"
26
#include "libavutil/intreadwrite.h"
27
#include "libavutil/mathematics.h"
28
#include "libavutil/mem.h"
29
#include "libavutil/random_seed.h"
30
#include "libavutil/time.h"
31
#include "avformat.h"
32
#include "demux.h"
33
34
#include "internal.h"
35
#include "network.h"
36
#include "os_support.h"
37
#include "rtpproto.h"
38
#include "rtsp.h"
39
#include "rdt.h"
40
#include "tls.h"
41
#include "url.h"
42
#include "version.h"
43
44
static const struct RTSPStatusMessage {
45
    enum RTSPStatusCode code;
46
    const char *message;
47
} status_messages[] = {
48
    { RTSP_STATUS_OK,             "OK"                               },
49
    { RTSP_STATUS_METHOD,         "Method Not Allowed"               },
50
    { RTSP_STATUS_BANDWIDTH,      "Not Enough Bandwidth"             },
51
    { RTSP_STATUS_SESSION,        "Session Not Found"                },
52
    { RTSP_STATUS_STATE,          "Method Not Valid in This State"   },
53
    { RTSP_STATUS_AGGREGATE,      "Aggregate operation not allowed"  },
54
    { RTSP_STATUS_ONLY_AGGREGATE, "Only aggregate operation allowed" },
55
    { RTSP_STATUS_TRANSPORT,      "Unsupported transport"            },
56
    { RTSP_STATUS_INTERNAL,       "Internal Server Error"            },
57
    { RTSP_STATUS_SERVICE,        "Service Unavailable"              },
58
    { RTSP_STATUS_VERSION,        "RTSP Version not supported"       },
59
    { 0,                          "NULL"                             }
60
};
61
62
static int rtsp_read_close(AVFormatContext *s)
63
0
{
64
0
    RTSPState *rt = s->priv_data;
65
66
0
    if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN))
67
0
        ff_rtsp_send_cmd_async(s, "TEARDOWN", rt->control_uri, NULL);
68
69
0
    ff_rtsp_close_streams(s);
70
0
    ff_rtsp_close_connections(s);
71
0
    ff_network_close();
72
0
    rt->real_setup = NULL;
73
0
    av_freep(&rt->real_setup_cache);
74
0
    return 0;
75
0
}
76
77
static inline int read_line(AVFormatContext *s, char *rbuf, const int rbufsize,
78
                            int *rbuflen)
79
0
{
80
0
    RTSPState *rt = s->priv_data;
81
0
    int idx       = 0;
82
0
    int ret       = 0;
83
0
    *rbuflen      = 0;
84
85
0
    do {
86
0
        ret = ffurl_read_complete(rt->rtsp_hd, rbuf + idx, 1);
87
0
        if (ret <= 0)
88
0
            return ret ? ret : AVERROR_EOF;
89
0
        if (rbuf[idx] == '\r') {
90
            /* Ignore */
91
0
        } else if (rbuf[idx] == '\n') {
92
0
            rbuf[idx] = '\0';
93
0
            *rbuflen  = idx;
94
0
            return 0;
95
0
        } else
96
0
            idx++;
97
0
    } while (idx < rbufsize);
98
0
    av_log(s, AV_LOG_ERROR, "Message too long\n");
99
0
    return AVERROR(EIO);
100
0
}
101
102
static int rtsp_send_reply(AVFormatContext *s, enum RTSPStatusCode code,
103
                           const char *extracontent, uint16_t seq)
104
0
{
105
0
    RTSPState *rt = s->priv_data;
106
0
    char message[MAX_URL_SIZE];
107
0
    int index = 0;
108
0
    while (status_messages[index].code) {
109
0
        if (status_messages[index].code == code) {
110
0
            snprintf(message, sizeof(message), "RTSP/1.0 %d %s\r\n",
111
0
                     code, status_messages[index].message);
112
0
            break;
113
0
        }
114
0
        index++;
115
0
    }
116
0
    if (!status_messages[index].code)
117
0
        return AVERROR(EINVAL);
118
0
    av_strlcatf(message, sizeof(message), "CSeq: %d\r\n", seq);
119
0
    av_strlcatf(message, sizeof(message), "Server: %s\r\n", LIBAVFORMAT_IDENT);
120
0
    if (extracontent)
121
0
        av_strlcat(message, extracontent, sizeof(message));
122
0
    av_strlcat(message, "\r\n", sizeof(message));
123
0
    av_log(s, AV_LOG_TRACE, "Sending response:\n%s", message);
124
0
    ffurl_write(rt->rtsp_hd_out, message, strlen(message));
125
126
0
    return 0;
127
0
}
128
129
static inline int check_sessionid(AVFormatContext *s,
130
                                  RTSPMessageHeader *request)
131
0
{
132
0
    RTSPState *rt = s->priv_data;
133
0
    unsigned char *session_id = rt->session_id;
134
0
    if (!session_id[0]) {
135
0
        av_log(s, AV_LOG_WARNING, "There is no session-id at the moment\n");
136
0
        return 0;
137
0
    }
138
0
    if (strcmp(session_id, request->session_id)) {
139
0
        av_log(s, AV_LOG_ERROR, "Unexpected session-id %s\n",
140
0
               request->session_id);
141
0
        rtsp_send_reply(s, RTSP_STATUS_SESSION, NULL, request->seq);
142
0
        return AVERROR_STREAM_NOT_FOUND;
143
0
    }
144
0
    return 0;
145
0
}
146
147
static inline int rtsp_read_request(AVFormatContext *s,
148
                                    RTSPMessageHeader *request,
149
                                    const char *method)
150
0
{
151
0
    RTSPState *rt = s->priv_data;
152
0
    char rbuf[MAX_URL_SIZE];
153
0
    int rbuflen, ret;
154
0
    do {
155
0
        ret = read_line(s, rbuf, sizeof(rbuf), &rbuflen);
156
0
        if (ret)
157
0
            return ret;
158
0
        if (rbuflen > 1) {
159
0
            av_log(s, AV_LOG_TRACE, "Parsing[%d]: %s\n", rbuflen, rbuf);
160
0
            ff_rtsp_parse_line(s, request, rbuf, rt, method);
161
0
        }
162
0
    } while (rbuflen > 0);
163
0
    if (request->seq != rt->seq + 1) {
164
0
        av_log(s, AV_LOG_ERROR, "Unexpected Sequence number %d\n",
165
0
               request->seq);
166
0
        return AVERROR(EINVAL);
167
0
    }
168
0
    if (rt->session_id[0] && strcmp(method, "OPTIONS")) {
169
0
        ret = check_sessionid(s, request);
170
0
        if (ret)
171
0
            return ret;
172
0
    }
173
174
0
    return 0;
175
0
}
176
177
static int rtsp_read_announce(AVFormatContext *s)
178
0
{
179
0
    RTSPState *rt             = s->priv_data;
180
0
    RTSPMessageHeader request = { 0 };
181
0
    char *sdp;
182
0
    int  ret;
183
184
0
    ret = rtsp_read_request(s, &request, "ANNOUNCE");
185
0
    if (ret)
186
0
        return ret;
187
0
    rt->seq++;
188
0
    if (strcmp(request.content_type, "application/sdp")) {
189
0
        av_log(s, AV_LOG_ERROR, "Unexpected content type %s\n",
190
0
               request.content_type);
191
0
        rtsp_send_reply(s, RTSP_STATUS_SERVICE, NULL, request.seq);
192
0
        return AVERROR_OPTION_NOT_FOUND;
193
0
    }
194
0
    if (request.content_length > 0 && request.content_length <= SDP_MAX_SIZE) {
195
0
        sdp = av_malloc(request.content_length + 1);
196
0
        if (!sdp)
197
0
            return AVERROR(ENOMEM);
198
199
        /* Read SDP */
200
0
        if (ffurl_read_complete(rt->rtsp_hd, sdp, request.content_length)
201
0
            < request.content_length) {
202
0
            av_log(s, AV_LOG_ERROR,
203
0
                   "Unable to get complete SDP Description in ANNOUNCE\n");
204
0
            rtsp_send_reply(s, RTSP_STATUS_INTERNAL, NULL, request.seq);
205
0
            av_free(sdp);
206
0
            return AVERROR(EIO);
207
0
        }
208
0
        sdp[request.content_length] = '\0';
209
0
        av_log(s, AV_LOG_VERBOSE, "SDP: %s\n", sdp);
210
0
        ret = ff_sdp_parse(s, sdp);
211
0
        av_free(sdp);
212
0
        if (ret)
213
0
            return ret;
214
0
        rtsp_send_reply(s, RTSP_STATUS_OK, NULL, request.seq);
215
0
        return 0;
216
0
    }
217
0
    av_log(s, AV_LOG_ERROR,
218
0
           "Invalid ANNOUNCE Content-Length %d\n", request.content_length);
219
0
    rtsp_send_reply(s, RTSP_STATUS_INTERNAL,
220
0
                    "Invalid Content-Length", request.seq);
221
0
    return AVERROR_INVALIDDATA;
222
0
}
223
224
static int rtsp_read_options(AVFormatContext *s)
225
0
{
226
0
    RTSPState *rt             = s->priv_data;
227
0
    RTSPMessageHeader request = { 0 };
228
0
    int ret                   = 0;
229
230
    /* Parsing headers */
231
0
    ret = rtsp_read_request(s, &request, "OPTIONS");
232
0
    if (ret)
233
0
        return ret;
234
0
    rt->seq++;
235
    /* Send Reply */
236
0
    rtsp_send_reply(s, RTSP_STATUS_OK,
237
0
                    "Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, RECORD\r\n",
238
0
                    request.seq);
239
0
    return 0;
240
0
}
241
242
static int rtsp_read_setup(AVFormatContext *s, char* host, char *controlurl)
243
0
{
244
0
    RTSPState *rt             = s->priv_data;
245
0
    RTSPMessageHeader request = { 0 };
246
0
    int ret                   = 0;
247
0
    char url[MAX_URL_SIZE];
248
0
    RTSPStream *rtsp_st;
249
0
    char responseheaders[MAX_URL_SIZE];
250
0
    int localport    = -1;
251
0
    int transportidx = 0;
252
0
    int streamid     = 0;
253
254
0
    ret = rtsp_read_request(s, &request, "SETUP");
255
0
    if (ret)
256
0
        return ret;
257
0
    rt->seq++;
258
0
    if (!request.nb_transports) {
259
0
        av_log(s, AV_LOG_ERROR, "No transport defined in SETUP\n");
260
0
        return AVERROR_INVALIDDATA;
261
0
    }
262
0
    for (transportidx = 0; transportidx < request.nb_transports;
263
0
         transportidx++) {
264
0
        if (!request.transports[transportidx].mode_record ||
265
0
            (request.transports[transportidx].lower_transport !=
266
0
             RTSP_LOWER_TRANSPORT_UDP &&
267
0
             request.transports[transportidx].lower_transport !=
268
0
             RTSP_LOWER_TRANSPORT_TCP)) {
269
0
            av_log(s, AV_LOG_ERROR, "mode=record/receive not set or transport"
270
0
                   " protocol not supported (yet)\n");
271
0
            return AVERROR_INVALIDDATA;
272
0
        }
273
0
    }
274
0
    if (request.nb_transports > 1)
275
0
        av_log(s, AV_LOG_WARNING, "More than one transport not supported, "
276
0
               "using first of all\n");
277
0
    for (streamid = 0; streamid < rt->nb_rtsp_streams; streamid++) {
278
0
        if (!strcmp(rt->rtsp_streams[streamid]->control_url,
279
0
                    controlurl))
280
0
            break;
281
0
    }
282
0
    if (streamid == rt->nb_rtsp_streams) {
283
0
        av_log(s, AV_LOG_ERROR, "Unable to find requested track\n");
284
0
        return AVERROR_STREAM_NOT_FOUND;
285
0
    }
286
0
    rtsp_st   = rt->rtsp_streams[streamid];
287
0
    localport = rt->rtp_port_min;
288
289
    /* check if the stream has already been setup */
290
0
    if (rtsp_st->transport_priv) {
291
0
        if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RDT)
292
0
            ff_rdt_parse_close(rtsp_st->transport_priv);
293
0
        else if (CONFIG_RTPDEC && rt->transport == RTSP_TRANSPORT_RTP)
294
0
            ff_rtp_parse_close(rtsp_st->transport_priv);
295
0
        rtsp_st->transport_priv = NULL;
296
0
    }
297
0
    if (rtsp_st->rtp_handle)
298
0
        ffurl_closep(&rtsp_st->rtp_handle);
299
300
0
    if (request.transports[0].lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
301
0
        rt->lower_transport = RTSP_LOWER_TRANSPORT_TCP;
302
0
        if ((ret = ff_rtsp_open_transport_ctx(s, rtsp_st))) {
303
0
            rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
304
0
            return ret;
305
0
        }
306
0
        rtsp_st->interleaved_min = request.transports[0].interleaved_min;
307
0
        rtsp_st->interleaved_max = request.transports[0].interleaved_max;
308
0
        snprintf(responseheaders, sizeof(responseheaders), "Transport: "
309
0
                 "RTP/AVP/TCP;unicast;mode=record;interleaved=%d-%d"
310
0
                 "\r\n", request.transports[0].interleaved_min,
311
0
                 request.transports[0].interleaved_max);
312
0
    } else {
313
0
        do {
314
0
            AVDictionary *opts = NULL;
315
0
            av_dict_set_int(&opts, "buffer_size", rt->buffer_size, 0);
316
0
            ff_url_join(url, sizeof(url), "rtp", NULL, host, localport, NULL);
317
0
            av_log(s, AV_LOG_TRACE, "Opening: %s\n", url);
318
0
            ret = ffurl_open_whitelist(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
319
0
                                       &s->interrupt_callback, &opts,
320
0
                                       s->protocol_whitelist, s->protocol_blacklist, NULL);
321
0
            av_dict_free(&opts);
322
0
            if (ret)
323
0
                localport += 2;
324
0
        } while (ret || localport > rt->rtp_port_max);
325
0
        if (localport > rt->rtp_port_max) {
326
0
            rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
327
0
            return ret;
328
0
        }
329
330
0
        av_log(s, AV_LOG_TRACE, "Listening on: %d\n",
331
0
                ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle));
332
0
        if ((ret = ff_rtsp_open_transport_ctx(s, rtsp_st))) {
333
0
            rtsp_send_reply(s, RTSP_STATUS_TRANSPORT, NULL, request.seq);
334
0
            return ret;
335
0
        }
336
337
0
        localport = ff_rtp_get_local_rtp_port(rtsp_st->rtp_handle);
338
0
        snprintf(responseheaders, sizeof(responseheaders), "Transport: "
339
0
                 "RTP/AVP/UDP;unicast;mode=record;source=%s;"
340
0
                 "client_port=%d-%d;server_port=%d-%d\r\n",
341
0
                 host, request.transports[0].client_port_min,
342
0
                 request.transports[0].client_port_max, localport,
343
0
                 localport + 1);
344
0
    }
345
346
    /* Establish sessionid if not previously set */
347
    /* Put this in a function? */
348
    /* RFC 2326: session id must be at least 8 digits */
349
0
    while (strlen(rt->session_id) < 8)
350
0
        av_strlcatf(rt->session_id, 512, "%u", av_get_random_seed());
351
352
0
    av_strlcatf(responseheaders, sizeof(responseheaders), "Session: %s\r\n",
353
0
                rt->session_id);
354
    /* Send Reply */
355
0
    rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq);
356
357
0
    rt->state = RTSP_STATE_PAUSED;
358
0
    return 0;
359
0
}
360
361
static int rtsp_read_record(AVFormatContext *s)
362
0
{
363
0
    RTSPState *rt             = s->priv_data;
364
0
    RTSPMessageHeader request = { 0 };
365
0
    int ret                   = 0;
366
0
    char responseheaders[MAX_URL_SIZE];
367
368
0
    ret = rtsp_read_request(s, &request, "RECORD");
369
0
    if (ret)
370
0
        return ret;
371
0
    ret = check_sessionid(s, &request);
372
0
    if (ret)
373
0
        return ret;
374
0
    rt->seq++;
375
0
    snprintf(responseheaders, sizeof(responseheaders), "Session: %s\r\n",
376
0
             rt->session_id);
377
0
    rtsp_send_reply(s, RTSP_STATUS_OK, responseheaders, request.seq);
378
379
0
    rt->state = RTSP_STATE_STREAMING;
380
0
    return 0;
381
0
}
382
383
static inline int parse_command_line(AVFormatContext *s, const char *line,
384
                                     int linelen, char *uri, int urisize,
385
                                     char *method, int methodsize,
386
                                     enum RTSPMethod *methodcode)
387
0
{
388
0
    RTSPState *rt = s->priv_data;
389
0
    const char *linept, *searchlinept;
390
0
    linept = strchr(line, ' ');
391
392
0
    if (!linept) {
393
0
        av_log(s, AV_LOG_ERROR, "Error parsing method string\n");
394
0
        return AVERROR_INVALIDDATA;
395
0
    }
396
397
0
    if (linept - line > methodsize - 1) {
398
0
        av_log(s, AV_LOG_ERROR, "Method string too long\n");
399
0
        return AVERROR(EIO);
400
0
    }
401
0
    memcpy(method, line, linept - line);
402
0
    method[linept - line] = '\0';
403
0
    linept++;
404
0
    if (!strcmp(method, "ANNOUNCE"))
405
0
        *methodcode = ANNOUNCE;
406
0
    else if (!strcmp(method, "OPTIONS"))
407
0
        *methodcode = OPTIONS;
408
0
    else if (!strcmp(method, "RECORD"))
409
0
        *methodcode = RECORD;
410
0
    else if (!strcmp(method, "SETUP"))
411
0
        *methodcode = SETUP;
412
0
    else if (!strcmp(method, "PAUSE"))
413
0
        *methodcode = PAUSE;
414
0
    else if (!strcmp(method, "TEARDOWN"))
415
0
        *methodcode = TEARDOWN;
416
0
    else
417
0
        *methodcode = UNKNOWN;
418
    /* Check method with the state  */
419
0
    if (rt->state == RTSP_STATE_IDLE) {
420
0
        if ((*methodcode != ANNOUNCE) && (*methodcode != OPTIONS)) {
421
0
            av_log(s, AV_LOG_ERROR, "Unexpected command in Idle State %s\n",
422
0
                   line);
423
0
            return AVERROR_PROTOCOL_NOT_FOUND;
424
0
        }
425
0
    } else if (rt->state == RTSP_STATE_PAUSED) {
426
0
        if ((*methodcode != OPTIONS) && (*methodcode != RECORD)
427
0
            && (*methodcode != SETUP)) {
428
0
            av_log(s, AV_LOG_ERROR, "Unexpected command in Paused State %s\n",
429
0
                   line);
430
0
            return AVERROR_PROTOCOL_NOT_FOUND;
431
0
        }
432
0
    } else if (rt->state == RTSP_STATE_STREAMING) {
433
0
        if ((*methodcode != PAUSE) && (*methodcode != OPTIONS)
434
0
            && (*methodcode != TEARDOWN)) {
435
0
            av_log(s, AV_LOG_ERROR, "Unexpected command in Streaming State"
436
0
                   " %s\n", line);
437
0
            return AVERROR_PROTOCOL_NOT_FOUND;
438
0
        }
439
0
    } else {
440
0
        av_log(s, AV_LOG_ERROR, "Unexpected State [%d]\n", rt->state);
441
0
        return AVERROR_BUG;
442
0
    }
443
444
0
    searchlinept = strchr(linept, ' ');
445
0
    if (!searchlinept) {
446
0
        av_log(s, AV_LOG_ERROR, "Error parsing message URI\n");
447
0
        return AVERROR_INVALIDDATA;
448
0
    }
449
0
    if (searchlinept - linept > urisize - 1) {
450
0
        av_log(s, AV_LOG_ERROR, "uri string length exceeded buffer size\n");
451
0
        return AVERROR(EIO);
452
0
    }
453
0
    memcpy(uri, linept, searchlinept - linept);
454
0
    uri[searchlinept - linept] = '\0';
455
0
    if (strcmp(rt->control_uri, uri)) {
456
0
        char host[128], path[512], auth[128];
457
0
        int port;
458
0
        char ctl_host[128], ctl_path[512], ctl_auth[128];
459
0
        int ctl_port;
460
0
        av_url_split(NULL, 0, auth, sizeof(auth), host, sizeof(host), &port,
461
0
                     path, sizeof(path), uri);
462
0
        av_url_split(NULL, 0, ctl_auth, sizeof(ctl_auth), ctl_host,
463
0
                     sizeof(ctl_host), &ctl_port, ctl_path, sizeof(ctl_path),
464
0
                     rt->control_uri);
465
0
        if (strcmp(host, ctl_host))
466
0
            av_log(s, AV_LOG_INFO, "Host %s differs from expected %s\n",
467
0
                   host, ctl_host);
468
0
        if (strcmp(path, ctl_path) && *methodcode != SETUP)
469
0
            av_log(s, AV_LOG_WARNING, "WARNING: Path %s differs from expected"
470
0
                   " %s\n", path, ctl_path);
471
0
        if (*methodcode == ANNOUNCE) {
472
0
            av_log(s, AV_LOG_INFO,
473
0
                   "Updating control URI to %s\n", uri);
474
0
            av_strlcpy(rt->control_uri, uri, sizeof(rt->control_uri));
475
0
        }
476
0
    }
477
478
0
    linept = searchlinept + 1;
479
0
    if (!av_strstart(linept, "RTSP/1.0", NULL)) {
480
0
        av_log(s, AV_LOG_ERROR, "Error parsing protocol or version\n");
481
0
        return AVERROR_PROTOCOL_NOT_FOUND;
482
0
    }
483
0
    return 0;
484
0
}
485
486
int ff_rtsp_parse_streaming_commands(AVFormatContext *s)
487
0
{
488
0
    RTSPState *rt = s->priv_data;
489
0
    unsigned char rbuf[MAX_URL_SIZE];
490
0
    unsigned char method[10];
491
0
    char uri[500];
492
0
    int ret;
493
0
    int rbuflen               = 0;
494
0
    RTSPMessageHeader request = { 0 };
495
0
    enum RTSPMethod methodcode;
496
497
0
    ret = read_line(s, rbuf, sizeof(rbuf), &rbuflen);
498
0
    if (ret < 0)
499
0
        return ret;
500
0
    av_log(s, AV_LOG_TRACE, "Parsing[%d]: %s\n", rbuflen, rbuf);
501
0
    ret = parse_command_line(s, rbuf, rbuflen, uri, sizeof(uri), method,
502
0
                             sizeof(method), &methodcode);
503
0
    if (ret) {
504
0
        av_log(s, AV_LOG_ERROR, "RTSP: Unexpected Command\n");
505
0
        return ret;
506
0
    }
507
508
0
    ret = rtsp_read_request(s, &request, method);
509
0
    if (ret)
510
0
        return ret;
511
0
    rt->seq++;
512
0
    if (methodcode == PAUSE) {
513
0
        rt->state = RTSP_STATE_PAUSED;
514
0
        ret       = rtsp_send_reply(s, RTSP_STATUS_OK, NULL , request.seq);
515
        // TODO: Missing date header in response
516
0
    } else if (methodcode == OPTIONS) {
517
0
        ret = rtsp_send_reply(s, RTSP_STATUS_OK,
518
0
                              "Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, "
519
0
                              "RECORD\r\n", request.seq);
520
0
    } else if (methodcode == TEARDOWN) {
521
0
        rt->state = RTSP_STATE_IDLE;
522
0
        ret       = rtsp_send_reply(s, RTSP_STATUS_OK, NULL , request.seq);
523
0
    }
524
0
    return ret;
525
0
}
526
527
static int rtsp_read_play(AVFormatContext *s)
528
0
{
529
0
    RTSPState *rt = s->priv_data;
530
0
    RTSPMessageHeader reply1, *reply = &reply1;
531
0
    int i;
532
0
    char cmd[MAX_URL_SIZE];
533
534
0
    av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state);
535
0
    rt->nb_byes = 0;
536
537
0
    if (rt->lower_transport == RTSP_LOWER_TRANSPORT_UDP) {
538
0
        for (i = 0; i < rt->nb_rtsp_streams; i++) {
539
0
            RTSPStream *rtsp_st = rt->rtsp_streams[i];
540
            /* Try to initialize the connection state in a
541
             * potential NAT router by sending dummy packets.
542
             * RTP/RTCP dummy packets are used for RDT, too.
543
             */
544
0
            if (rtsp_st->rtp_handle &&
545
0
                !(rt->server_type == RTSP_SERVER_WMS && i > 1))
546
0
                ff_rtp_send_punch_packets(rtsp_st->rtp_handle);
547
0
        }
548
0
    }
549
0
    if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
550
0
        if (rt->transport == RTSP_TRANSPORT_RTP) {
551
0
            for (i = 0; i < rt->nb_rtsp_streams; i++) {
552
0
                RTSPStream *rtsp_st = rt->rtsp_streams[i];
553
0
                RTPDemuxContext *rtpctx = rtsp_st->transport_priv;
554
0
                if (!rtpctx)
555
0
                    continue;
556
0
                ff_rtp_reset_packet_queue(rtpctx);
557
0
                rtpctx->last_sr.ntp_timestamp = AV_NOPTS_VALUE;
558
0
                rtpctx->first_rtcp_ntp_time = AV_NOPTS_VALUE;
559
0
                rtpctx->base_timestamp      = 0;
560
0
                rtpctx->timestamp           = 0;
561
0
                rtpctx->unwrapped_timestamp = 0;
562
0
                rtpctx->rtcp_ts_offset      = 0;
563
0
            }
564
0
        }
565
0
        if (rt->state == RTSP_STATE_PAUSED) {
566
0
            cmd[0] = 0;
567
0
        } else {
568
0
            snprintf(cmd, sizeof(cmd),
569
0
                     "Range: npt=%"PRId64".%03"PRId64"-\r\n",
570
0
                     rt->seek_timestamp / AV_TIME_BASE,
571
0
                     rt->seek_timestamp / (AV_TIME_BASE / 1000) % 1000);
572
0
        }
573
0
        ff_rtsp_send_cmd(s, "PLAY", rt->control_uri, cmd, reply, NULL);
574
0
        if (reply->status_code != RTSP_STATUS_OK) {
575
0
            return ff_rtsp_averror(reply->status_code, -1);
576
0
        }
577
0
        if (rt->transport == RTSP_TRANSPORT_RTP &&
578
0
            reply->range_start != AV_NOPTS_VALUE) {
579
0
            for (i = 0; i < rt->nb_rtsp_streams; i++) {
580
0
                RTSPStream *rtsp_st = rt->rtsp_streams[i];
581
0
                RTPDemuxContext *rtpctx = rtsp_st->transport_priv;
582
0
                AVStream *st = NULL;
583
0
                if (!rtpctx || rtsp_st->stream_index < 0)
584
0
                    continue;
585
586
0
                st = s->streams[rtsp_st->stream_index];
587
0
                rtpctx->range_start_offset =
588
0
                    av_rescale_q(reply->range_start, AV_TIME_BASE_Q,
589
0
                                 st->time_base);
590
0
            }
591
0
        }
592
0
    }
593
0
    rt->state = RTSP_STATE_STREAMING;
594
0
    return 0;
595
0
}
596
597
/* pause the stream */
598
static int rtsp_read_pause(AVFormatContext *s)
599
0
{
600
0
    RTSPState *rt = s->priv_data;
601
0
    RTSPMessageHeader reply1, *reply = &reply1;
602
603
0
    if (rt->state != RTSP_STATE_STREAMING)
604
0
        return 0;
605
0
    else if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
606
0
        ff_rtsp_send_cmd(s, "PAUSE", rt->control_uri, NULL, reply, NULL);
607
0
        if (reply->status_code != RTSP_STATUS_OK) {
608
0
            return ff_rtsp_averror(reply->status_code, -1);
609
0
        }
610
0
    }
611
0
    rt->state = RTSP_STATE_PAUSED;
612
0
    return 0;
613
0
}
614
615
static int rtsp_read_set_state(AVFormatContext *s,
616
                               enum FFInputFormatStreamState state)
617
0
{
618
0
    switch (state) {
619
0
        case FF_INFMT_STATE_PLAY:
620
0
            return rtsp_read_play(s);
621
0
        case FF_INFMT_STATE_PAUSE:
622
0
            return rtsp_read_pause(s);
623
0
        default:
624
0
            return AVERROR(ENOTSUP);
625
0
    }
626
0
}
627
628
static char *dict_to_headers(AVDictionary *headers)
629
0
{
630
0
    char *buf;
631
0
    AVBPrint bprint;
632
0
    av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED);
633
634
0
    const AVDictionaryEntry *header = NULL;
635
0
    while ((header = av_dict_iterate(headers, header))) {
636
0
        av_bprintf(&bprint, "%s: %s\r\n", header->key, header->value);
637
0
    }
638
639
0
    av_bprint_finalize(&bprint, &buf);
640
0
    return buf;
641
0
}
642
643
static int rtsp_submit_command(struct AVFormatContext *s, enum AVFormatCommandID id, void *data)
644
0
{
645
0
    if (id != AVFORMAT_COMMAND_RTSP_SET_PARAMETER)
646
0
        return AVERROR(ENOTSUP);
647
0
    if (!data)
648
0
        return AVERROR(EINVAL);
649
650
0
    RTSPState *rt = s->priv_data;
651
0
    AVRTSPCommandRequest *req = data;
652
653
0
    if (rt->state == RTSP_STATE_IDLE)
654
        // Not ready to send a SET_PARAMETERS command yet
655
0
        return AVERROR(EAGAIN);
656
657
0
    av_log(s, AV_LOG_DEBUG, "Sending SET_PARAMETER command to %s\n", rt->control_uri);
658
0
    char *headers = dict_to_headers(req->headers);
659
660
0
    int ret = ff_rtsp_send_cmd_with_content_async_stored(s, "SET_PARAMETER",
661
0
        rt->control_uri, headers, req->body, req->body_len);
662
0
    av_free(headers);
663
664
0
    if (ret != 0)
665
0
        av_log(s, AV_LOG_ERROR, "Failure sending SET_PARAMETER command: %s\n", av_err2str(ret));
666
667
0
    return ret;
668
0
}
669
670
static int rtsp_read_command_reply(AVFormatContext *s, enum AVFormatCommandID id, void **data_out)
671
0
{
672
0
    if (id != AVFORMAT_COMMAND_RTSP_SET_PARAMETER)
673
0
        return AVERROR(ENOTSUP);
674
0
    if (!data_out)
675
0
        return AVERROR(EINVAL);
676
677
0
    unsigned char *body;
678
0
    RTSPMessageHeader *reply;
679
0
    int ret = ff_rtsp_read_reply_async_stored(s, &reply, &body);
680
0
    if (ret < 0)
681
0
        return ret;
682
683
0
    AVRTSPResponse *res = av_malloc(sizeof(*res));
684
0
    if (!res) {
685
0
        av_free(body);
686
0
        av_free(reply);
687
0
        return AVERROR(ENOMEM);
688
0
    }
689
690
0
    res->status_code = reply->status_code;
691
0
    res->body_len = reply->content_length;
692
0
    res->body = body;
693
694
0
    res->reason = av_strdup(reply->reason);
695
0
    if (!res->reason) {
696
0
        av_free(res->body);
697
0
        av_free(res);
698
0
        av_free(reply);
699
0
        return AVERROR(ENOMEM);
700
0
    }
701
702
0
    av_free(reply);
703
0
    *data_out = res;
704
0
    return 0;
705
0
}
706
707
static int rtsp_handle_command(struct AVFormatContext *s,
708
    enum FFInputFormatCommandOption opt,
709
    enum AVFormatCommandID id, void *data)
710
0
{
711
0
    switch (opt) {
712
0
        case FF_INFMT_COMMAND_SUBMIT:
713
0
        return rtsp_submit_command(s, id, data);
714
0
        case FF_INFMT_COMMAND_GET_REPLY:
715
0
        return rtsp_read_command_reply(s, id, data);
716
0
        default:
717
0
        av_unreachable("Invalid command option");
718
0
    }
719
0
}
720
721
int ff_rtsp_setup_input_streams(AVFormatContext *s, RTSPMessageHeader *reply)
722
0
{
723
0
    RTSPState *rt = s->priv_data;
724
0
    char cmd[MAX_URL_SIZE];
725
0
    unsigned char *content = NULL;
726
0
    int ret;
727
728
    /* describe the stream */
729
0
    snprintf(cmd, sizeof(cmd),
730
0
             "Accept: application/sdp\r\n");
731
0
    if (rt->server_type == RTSP_SERVER_REAL) {
732
        /**
733
         * The Require: attribute is needed for proper streaming from
734
         * Realmedia servers.
735
         */
736
0
        av_strlcat(cmd,
737
0
                   "Require: com.real.retain-entity-for-setup\r\n",
738
0
                   sizeof(cmd));
739
0
    }
740
0
    ff_rtsp_send_cmd(s, "DESCRIBE", rt->control_uri, cmd, reply, &content);
741
0
    if (reply->status_code != RTSP_STATUS_OK) {
742
0
        av_freep(&content);
743
0
        return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
744
0
    }
745
0
    if (!content)
746
0
        return AVERROR_INVALIDDATA;
747
748
0
    av_log(s, AV_LOG_VERBOSE, "SDP:\n%s\n", content);
749
    /* now we got the SDP description, we parse it */
750
0
    ret = ff_sdp_parse(s, (const char *)content);
751
0
    av_freep(&content);
752
0
    if (ret < 0)
753
0
        return ret;
754
755
0
    return 0;
756
0
}
757
758
static int rtsp_listen(AVFormatContext *s)
759
0
{
760
0
    RTSPState *rt = s->priv_data;
761
0
    char proto[128], host[128], path[512], auth[128];
762
0
    char uri[500];
763
0
    int port;
764
0
    int default_port = RTSP_DEFAULT_PORT;
765
0
    char tcpname[500];
766
0
    const char *lower_proto = "tcp";
767
0
    unsigned char rbuf[MAX_URL_SIZE];
768
0
    unsigned char method[10];
769
0
    int rbuflen = 0;
770
0
    int ret;
771
0
    enum RTSPMethod methodcode;
772
773
0
    if ((ret = ff_network_init()) < 0)
774
0
        return ret;
775
776
    /* extract hostname and port */
777
0
    av_url_split(proto, sizeof(proto), auth, sizeof(auth), host, sizeof(host),
778
0
                 &port, path, sizeof(path), s->url);
779
780
    /* ff_url_join. No authorization by now (NULL) */
781
0
    ff_url_join(rt->control_uri, sizeof(rt->control_uri), proto, NULL, host,
782
0
                port, "%s", path);
783
784
0
    if (!strcmp(proto, "rtsps")) {
785
0
        lower_proto  = "tls";
786
0
        default_port = RTSPS_DEFAULT_PORT;
787
0
    }
788
789
0
    if (port < 0)
790
0
        port = default_port;
791
792
    /* Create TCP connection */
793
0
    ff_url_join(tcpname, sizeof(tcpname), lower_proto, NULL, host, port,
794
0
                "?listen&listen_timeout=%d", rt->initial_timeout * 1000);
795
796
0
    if (ret = ffurl_open_whitelist(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,
797
0
                                   &s->interrupt_callback, NULL,
798
0
                                   s->protocol_whitelist, s->protocol_blacklist, NULL)) {
799
0
        av_log(s, AV_LOG_ERROR, "Unable to open RTSP for listening\n");
800
0
        goto fail;
801
0
    }
802
0
    rt->state       = RTSP_STATE_IDLE;
803
0
    rt->rtsp_hd_out = rt->rtsp_hd;
804
0
    for (;;) { /* Wait for incoming RTSP messages */
805
0
        ret = read_line(s, rbuf, sizeof(rbuf), &rbuflen);
806
0
        if (ret < 0)
807
0
            goto fail;
808
0
        av_log(s, AV_LOG_TRACE, "Parsing[%d]: %s\n", rbuflen, rbuf);
809
0
        ret = parse_command_line(s, rbuf, rbuflen, uri, sizeof(uri), method,
810
0
                                 sizeof(method), &methodcode);
811
0
        if (ret) {
812
0
            av_log(s, AV_LOG_ERROR, "RTSP: Unexpected Command\n");
813
0
            goto fail;
814
0
        }
815
816
0
        if (methodcode == ANNOUNCE) {
817
0
            ret       = rtsp_read_announce(s);
818
0
            rt->state = RTSP_STATE_PAUSED;
819
0
        } else if (methodcode == OPTIONS) {
820
0
            ret = rtsp_read_options(s);
821
0
        } else if (methodcode == RECORD) {
822
0
            ret = rtsp_read_record(s);
823
0
            if (!ret)
824
0
                return 0; // We are ready for streaming
825
0
        } else if (methodcode == SETUP)
826
0
            ret = rtsp_read_setup(s, host, uri);
827
0
        if (ret) {
828
0
            ret = AVERROR_INVALIDDATA;
829
0
            goto fail;
830
0
        }
831
0
    }
832
0
fail:
833
0
    ff_rtsp_close_streams(s);
834
0
    ff_rtsp_close_connections(s);
835
0
    ff_network_close();
836
0
    return ret;
837
0
}
838
839
static int rtsp_probe(const AVProbeData *p)
840
0
{
841
0
    if (
842
#if CONFIG_TLS_PROTOCOL
843
        av_strstart(p->filename, "rtsps:", NULL) ||
844
#endif
845
0
        av_strstart(p->filename, "satip:", NULL) ||
846
0
        av_strstart(p->filename, "rtsp:", NULL))
847
0
        return AVPROBE_SCORE_MAX;
848
0
    return 0;
849
0
}
850
851
static int rtsp_read_header(AVFormatContext *s)
852
0
{
853
0
    RTSPState *rt = s->priv_data;
854
0
    int ret;
855
856
0
    if (rt->initial_timeout > 0)
857
0
        rt->rtsp_flags |= RTSP_FLAG_LISTEN;
858
859
0
    if (rt->rtsp_flags & RTSP_FLAG_LISTEN) {
860
0
        ret = rtsp_listen(s);
861
0
        if (ret)
862
0
            return ret;
863
0
    } else {
864
0
        ret = ff_rtsp_connect(s);
865
0
        if (ret)
866
0
            return ret;
867
868
0
        rt->real_setup_cache = !s->nb_streams ? NULL :
869
0
            av_calloc(s->nb_streams, 2 * sizeof(*rt->real_setup_cache));
870
0
        if (!rt->real_setup_cache && s->nb_streams) {
871
0
            ret = AVERROR(ENOMEM);
872
0
            goto fail;
873
0
        }
874
0
        rt->real_setup = rt->real_setup_cache + s->nb_streams;
875
876
0
        if (rt->initial_pause) {
877
            /* do not start immediately */
878
0
        } else {
879
0
            ret = rtsp_read_play(s);
880
0
            if (ret < 0)
881
0
                goto fail;
882
0
        }
883
0
    }
884
885
0
    return 0;
886
887
0
fail:
888
0
    rtsp_read_close(s);
889
0
    return ret;
890
0
}
891
892
int ff_rtsp_tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
893
                            uint8_t *buf, int buf_size)
894
0
{
895
0
    RTSPState *rt = s->priv_data;
896
0
    int id, len, i, ret;
897
0
    RTSPStream *rtsp_st;
898
899
0
    av_log(s, AV_LOG_TRACE, "tcp_read_packet:\n");
900
0
redo:
901
0
    for (;;) {
902
0
        RTSPMessageHeader reply;
903
904
0
        ret = ff_rtsp_read_reply(s, &reply, NULL, 1, NULL);
905
0
        if (ret < 0)
906
0
            return ret;
907
0
        if (ret == 1) /* received '$' */
908
0
            break;
909
        /* XXX: parse message */
910
0
        if (rt->state != RTSP_STATE_STREAMING)
911
0
            return 0;
912
0
    }
913
0
    ret = ffurl_read_complete(rt->rtsp_hd, buf, 3);
914
0
    if (ret != 3)
915
0
        return AVERROR(EIO);
916
0
    rt->pending_packet = 0;
917
0
    id  = buf[0];
918
0
    len = AV_RB16(buf + 1);
919
0
    av_log(s, AV_LOG_TRACE, "id=%d len=%d\n", id, len);
920
0
    if (len > buf_size || len < 8)
921
0
        goto redo;
922
    /* get the data */
923
0
    ret = ffurl_read_complete(rt->rtsp_hd, buf, len);
924
0
    if (ret != len)
925
0
        return AVERROR(EIO);
926
0
    if (rt->transport == RTSP_TRANSPORT_RDT &&
927
0
        (ret = ff_rdt_parse_header(buf, len, &id, NULL, NULL, NULL, NULL)) < 0)
928
0
        return ret;
929
930
    /* find the matching stream */
931
0
    for (i = 0; i < rt->nb_rtsp_streams; i++) {
932
0
        rtsp_st = rt->rtsp_streams[i];
933
0
        if (id >= rtsp_st->interleaved_min &&
934
0
            id <= rtsp_st->interleaved_max)
935
0
            goto found;
936
0
    }
937
0
    goto redo;
938
0
found:
939
0
    *prtsp_st = rtsp_st;
940
0
    return len;
941
0
}
942
943
static int resetup_tcp(AVFormatContext *s)
944
0
{
945
0
    RTSPState *rt = s->priv_data;
946
0
    char host[1024];
947
0
    int port;
948
949
0
    av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0,
950
0
                 s->url);
951
0
    ff_rtsp_undo_setup(s, 0);
952
0
    return ff_rtsp_make_setup_request(s, host, port, RTSP_LOWER_TRANSPORT_TCP,
953
0
                                      rt->real_challenge);
954
0
}
955
956
static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt)
957
0
{
958
0
    RTSPState *rt = s->priv_data;
959
0
    int ret;
960
0
    RTSPMessageHeader reply1, *reply = &reply1;
961
0
    char cmd[MAX_URL_SIZE];
962
963
0
retry:
964
0
    if (rt->server_type == RTSP_SERVER_REAL) {
965
0
        int i;
966
967
0
        for (i = 0; i < s->nb_streams; i++)
968
0
            rt->real_setup[i] = s->streams[i]->discard;
969
970
0
        if (!rt->need_subscription) {
971
0
            if (memcmp (rt->real_setup, rt->real_setup_cache,
972
0
                        sizeof(enum AVDiscard) * s->nb_streams)) {
973
0
                snprintf(cmd, sizeof(cmd),
974
0
                         "Unsubscribe: %s\r\n",
975
0
                         rt->last_subscription);
976
0
                ff_rtsp_send_cmd(s, "SET_PARAMETER", rt->control_uri,
977
0
                                 cmd, reply, NULL);
978
0
                if (reply->status_code != RTSP_STATUS_OK)
979
0
                    return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
980
0
                rt->need_subscription = 1;
981
0
            }
982
0
        }
983
984
0
        if (rt->need_subscription) {
985
0
            int r, rule_nr, first = 1;
986
987
0
            memcpy(rt->real_setup_cache, rt->real_setup,
988
0
                   sizeof(enum AVDiscard) * s->nb_streams);
989
0
            rt->last_subscription[0] = 0;
990
991
0
            snprintf(cmd, sizeof(cmd),
992
0
                     "Subscribe: ");
993
0
            for (i = 0; i < rt->nb_rtsp_streams; i++) {
994
0
                rule_nr = 0;
995
0
                for (r = 0; r < s->nb_streams; r++) {
996
0
                    if (s->streams[r]->id == i) {
997
0
                        if (s->streams[r]->discard != AVDISCARD_ALL) {
998
0
                            if (!first)
999
0
                                av_strlcat(rt->last_subscription, ",",
1000
0
                                           sizeof(rt->last_subscription));
1001
0
                            ff_rdt_subscribe_rule(
1002
0
                                rt->last_subscription,
1003
0
                                sizeof(rt->last_subscription), i, rule_nr);
1004
0
                            first = 0;
1005
0
                        }
1006
0
                        rule_nr++;
1007
0
                    }
1008
0
                }
1009
0
            }
1010
0
            av_strlcatf(cmd, sizeof(cmd), "%s\r\n", rt->last_subscription);
1011
0
            ff_rtsp_send_cmd(s, "SET_PARAMETER", rt->control_uri,
1012
0
                             cmd, reply, NULL);
1013
0
            if (reply->status_code != RTSP_STATUS_OK)
1014
0
                return ff_rtsp_averror(reply->status_code, AVERROR_INVALIDDATA);
1015
0
            rt->need_subscription = 0;
1016
1017
0
            if (rt->state == RTSP_STATE_STREAMING)
1018
0
                rtsp_read_play (s);
1019
0
        }
1020
0
    }
1021
1022
0
    ret = ff_rtsp_fetch_packet(s, pkt);
1023
0
    if (ret < 0) {
1024
0
        if (ret == AVERROR(ETIMEDOUT) && !rt->packets) {
1025
0
            if (rt->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
1026
0
                rt->lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_TCP)) {
1027
0
                RTSPMessageHeader reply1, *reply = &reply1;
1028
0
                av_log(s, AV_LOG_WARNING, "UDP timeout, retrying with TCP\n");
1029
0
                if (rtsp_read_pause(s) != 0)
1030
0
                    return -1;
1031
                // TEARDOWN is required on Real-RTSP, but might make
1032
                // other servers close the connection.
1033
0
                if (rt->server_type == RTSP_SERVER_REAL)
1034
0
                    ff_rtsp_send_cmd(s, "TEARDOWN", rt->control_uri, NULL,
1035
0
                                     reply, NULL);
1036
0
                rt->session_id[0] = '\0';
1037
0
                if (resetup_tcp(s) == 0) {
1038
0
                    rt->state = RTSP_STATE_IDLE;
1039
0
                    rt->need_subscription = 1;
1040
0
                    if (rtsp_read_play(s) != 0)
1041
0
                        return -1;
1042
0
                    goto retry;
1043
0
                }
1044
0
            }
1045
0
        }
1046
0
        return ret;
1047
0
    }
1048
0
    rt->packets++;
1049
1050
0
    if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN)) {
1051
        /* send dummy request to keep TCP connection alive */
1052
0
        if ((av_gettime_relative() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2 ||
1053
0
            rt->auth_state.stale) {
1054
0
            if (rt->server_type == RTSP_SERVER_WMS ||
1055
0
                (rt->server_type != RTSP_SERVER_REAL &&
1056
0
                 rt->get_parameter_supported)) {
1057
0
                ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL);
1058
0
            } else {
1059
0
                ff_rtsp_send_cmd_async(s, "OPTIONS", rt->control_uri, NULL);
1060
0
            }
1061
            /* The stale flag should be reset when creating the auth response in
1062
             * ff_rtsp_send_cmd_async, but reset it here just in case we never
1063
             * called the auth code (if we didn't have any credentials set). */
1064
0
            rt->auth_state.stale = 0;
1065
0
        }
1066
0
    }
1067
1068
0
    return 0;
1069
0
}
1070
1071
static int rtsp_read_seek(AVFormatContext *s, int stream_index,
1072
                          int64_t timestamp, int flags)
1073
0
{
1074
0
    RTSPState *rt = s->priv_data;
1075
0
    int ret;
1076
1077
0
    rt->seek_timestamp = av_rescale_q(timestamp,
1078
0
                                      s->streams[stream_index]->time_base,
1079
0
                                      AV_TIME_BASE_Q);
1080
0
    switch(rt->state) {
1081
0
    default:
1082
0
    case RTSP_STATE_IDLE:
1083
0
        break;
1084
0
    case RTSP_STATE_STREAMING:
1085
0
        if ((ret = rtsp_read_pause(s)) != 0)
1086
0
            return ret;
1087
0
        rt->state = RTSP_STATE_SEEKING;
1088
0
        if ((ret = rtsp_read_play(s)) != 0)
1089
0
            return ret;
1090
0
        break;
1091
0
    case RTSP_STATE_PAUSED:
1092
0
        rt->state = RTSP_STATE_IDLE;
1093
0
        break;
1094
0
    }
1095
0
    return 0;
1096
0
}
1097
1098
static const AVClass rtsp_demuxer_class = {
1099
    .class_name     = "RTSP demuxer",
1100
    .item_name      = av_default_item_name,
1101
    .option         = ff_rtsp_options,
1102
    .version        = LIBAVUTIL_VERSION_INT,
1103
};
1104
1105
const FFInputFormat ff_rtsp_demuxer = {
1106
    .p.name         = "rtsp",
1107
    .p.long_name    = NULL_IF_CONFIG_SMALL("RTSP input"),
1108
    .p.flags        = AVFMT_NOFILE,
1109
    .p.priv_class   = &rtsp_demuxer_class,
1110
    .priv_data_size = sizeof(RTSPState),
1111
    .read_probe     = rtsp_probe,
1112
    .read_header    = rtsp_read_header,
1113
    .read_packet    = rtsp_read_packet,
1114
    .read_close     = rtsp_read_close,
1115
    .read_seek      = rtsp_read_seek,
1116
    .read_set_state = rtsp_read_set_state,
1117
    .handle_command = rtsp_handle_command,
1118
};