FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/rtspdec.c
Date: 2026-10-04 16:07:23
Exec Total Coverage
Lines: 5 658 0.8%
Functions: 1 26 3.8%
Branches: 2 377 0.5%

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