3 * Copyright (c) 2002 Fabrice Bellard
5 * This file is part of FFmpeg.
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.
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.
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
22 #include "libavutil/avstring.h"
23 #include "libavutil/intreadwrite.h"
24 #include "libavutil/mathematics.h"
25 #include "libavutil/random_seed.h"
26 #include "libavutil/time.h"
31 #include "os_support.h"
37 static const struct RTSPStatusMessage
{
38 enum RTSPStatusCode code
;
40 } status_messages
[] = {
41 { RTSP_STATUS_OK
, "OK" },
42 { RTSP_STATUS_METHOD
, "Method Not Allowed" },
43 { RTSP_STATUS_BANDWIDTH
, "Not Enough Bandwidth" },
44 { RTSP_STATUS_SESSION
, "Session Not Found" },
45 { RTSP_STATUS_STATE
, "Method Not Valid in This State" },
46 { RTSP_STATUS_AGGREGATE
, "Aggregate operation not allowed" },
47 { RTSP_STATUS_ONLY_AGGREGATE
, "Only aggregate operation allowed" },
48 { RTSP_STATUS_TRANSPORT
, "Unsupported transport" },
49 { RTSP_STATUS_INTERNAL
, "Internal Server Error" },
50 { RTSP_STATUS_SERVICE
, "Service Unavailable" },
51 { RTSP_STATUS_VERSION
, "RTSP Version not supported" },
55 static int rtsp_read_close(AVFormatContext
*s
)
57 RTSPState
*rt
= s
->priv_data
;
59 if (!(rt
->rtsp_flags
& RTSP_FLAG_LISTEN
))
60 ff_rtsp_send_cmd_async(s
, "TEARDOWN", rt
->control_uri
, NULL
);
62 ff_rtsp_close_streams(s
);
63 ff_rtsp_close_connections(s
);
65 rt
->real_setup
= NULL
;
66 av_freep(&rt
->real_setup_cache
);
70 static inline int read_line(AVFormatContext
*s
, char *rbuf
, const int rbufsize
,
73 RTSPState
*rt
= s
->priv_data
;
79 ret
= ffurl_read_complete(rt
->rtsp_hd
, rbuf
+ idx
, 1);
81 return ret
? ret
: AVERROR_EOF
;
82 if (rbuf
[idx
] == '\r') {
84 } else if (rbuf
[idx
] == '\n') {
90 } while (idx
< rbufsize
);
91 av_log(s
, AV_LOG_ERROR
, "Message too long\n");
95 static int rtsp_send_reply(AVFormatContext
*s
, enum RTSPStatusCode code
,
96 const char *extracontent
, uint16_t seq
)
98 RTSPState
*rt
= s
->priv_data
;
101 while (status_messages
[index
].code
) {
102 if (status_messages
[index
].code
== code
) {
103 snprintf(message
, sizeof(message
), "RTSP/1.0 %d %s\r\n",
104 code
, status_messages
[index
].message
);
109 if (!status_messages
[index
].code
)
110 return AVERROR(EINVAL
);
111 av_strlcatf(message
, sizeof(message
), "CSeq: %d\r\n", seq
);
112 av_strlcatf(message
, sizeof(message
), "Server: %s\r\n", LIBAVFORMAT_IDENT
);
114 av_strlcat(message
, extracontent
, sizeof(message
));
115 av_strlcat(message
, "\r\n", sizeof(message
));
116 av_dlog(s
, "Sending response:\n%s", message
);
117 ffurl_write(rt
->rtsp_hd
, message
, strlen(message
));
122 static inline int check_sessionid(AVFormatContext
*s
,
123 RTSPMessageHeader
*request
)
125 RTSPState
*rt
= s
->priv_data
;
126 unsigned char *session_id
= rt
->session_id
;
127 if (!session_id
[0]) {
128 av_log(s
, AV_LOG_WARNING
, "There is no session-id at the moment\n");
131 if (strcmp(session_id
, request
->session_id
)) {
132 av_log(s
, AV_LOG_ERROR
, "Unexpected session-id %s\n",
133 request
->session_id
);
134 rtsp_send_reply(s
, RTSP_STATUS_SESSION
, NULL
, request
->seq
);
135 return AVERROR_STREAM_NOT_FOUND
;
140 static inline int rtsp_read_request(AVFormatContext
*s
,
141 RTSPMessageHeader
*request
,
144 RTSPState
*rt
= s
->priv_data
;
148 ret
= read_line(s
, rbuf
, sizeof(rbuf
), &rbuflen
);
152 av_dlog(s
, "Parsing[%d]: %s\n", rbuflen
, rbuf
);
153 ff_rtsp_parse_line(request
, rbuf
, rt
, method
);
155 } while (rbuflen
> 0);
156 if (request
->seq
!= rt
->seq
+ 1) {
157 av_log(s
, AV_LOG_ERROR
, "Unexpected Sequence number %d\n",
159 return AVERROR(EINVAL
);
161 if (rt
->session_id
[0] && strcmp(method
, "OPTIONS")) {
162 ret
= check_sessionid(s
, request
);
170 static int rtsp_read_announce(AVFormatContext
*s
)
172 RTSPState
*rt
= s
->priv_data
;
173 RTSPMessageHeader request
= { 0 };
177 ret
= rtsp_read_request(s
, &request
, "ANNOUNCE");
181 if (strcmp(request
.content_type
, "application/sdp")) {
182 av_log(s
, AV_LOG_ERROR
, "Unexpected content type %s\n",
183 request
.content_type
);
184 rtsp_send_reply(s
, RTSP_STATUS_SERVICE
, NULL
, request
.seq
);
185 return AVERROR_OPTION_NOT_FOUND
;
187 if (request
.content_length
&& request
.content_length
< sizeof(sdp
) - 1) {
189 if (ffurl_read_complete(rt
->rtsp_hd
, sdp
, request
.content_length
)
190 < request
.content_length
) {
191 av_log(s
, AV_LOG_ERROR
,
192 "Unable to get complete SDP Description in ANNOUNCE\n");
193 rtsp_send_reply(s
, RTSP_STATUS_INTERNAL
, NULL
, request
.seq
);
196 sdp
[request
.content_length
] = '\0';
197 av_log(s
, AV_LOG_VERBOSE
, "SDP: %s\n", sdp
);
198 ret
= ff_sdp_parse(s
, sdp
);
201 rtsp_send_reply(s
, RTSP_STATUS_OK
, NULL
, request
.seq
);
204 av_log(s
, AV_LOG_ERROR
,
205 "Content-Length header value exceeds sdp allocated buffer (4KB)\n");
206 rtsp_send_reply(s
, RTSP_STATUS_INTERNAL
,
207 "Content-Length exceeds buffer size", request
.seq
);
211 static int rtsp_read_options(AVFormatContext
*s
)
213 RTSPState
*rt
= s
->priv_data
;
214 RTSPMessageHeader request
= { 0 };
217 /* Parsing headers */
218 ret
= rtsp_read_request(s
, &request
, "OPTIONS");
223 rtsp_send_reply(s
, RTSP_STATUS_OK
,
224 "Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, RECORD\r\n",
229 static int rtsp_read_setup(AVFormatContext
*s
, char* host
, char *controlurl
)
231 RTSPState
*rt
= s
->priv_data
;
232 RTSPMessageHeader request
= { 0 };
236 char responseheaders
[1024];
238 int transportidx
= 0;
241 ret
= rtsp_read_request(s
, &request
, "SETUP");
245 if (!request
.nb_transports
) {
246 av_log(s
, AV_LOG_ERROR
, "No transport defined in SETUP\n");
247 return AVERROR_INVALIDDATA
;
249 for (transportidx
= 0; transportidx
< request
.nb_transports
;
251 if (!request
.transports
[transportidx
].mode_record
||
252 (request
.transports
[transportidx
].lower_transport
!=
253 RTSP_LOWER_TRANSPORT_UDP
&&
254 request
.transports
[transportidx
].lower_transport
!=
255 RTSP_LOWER_TRANSPORT_TCP
)) {
256 av_log(s
, AV_LOG_ERROR
, "mode=record/receive not set or transport"
257 " protocol not supported (yet)\n");
258 return AVERROR_INVALIDDATA
;
261 if (request
.nb_transports
> 1)
262 av_log(s
, AV_LOG_WARNING
, "More than one transport not supported, "
263 "using first of all\n");
264 for (streamid
= 0; streamid
< rt
->nb_rtsp_streams
; streamid
++) {
265 if (!strcmp(rt
->rtsp_streams
[streamid
]->control_url
,
269 if (streamid
== rt
->nb_rtsp_streams
) {
270 av_log(s
, AV_LOG_ERROR
, "Unable to find requested track\n");
271 return AVERROR_STREAM_NOT_FOUND
;
273 rtsp_st
= rt
->rtsp_streams
[streamid
];
274 localport
= rt
->rtp_port_min
;
276 if (request
.transports
[0].lower_transport
== RTSP_LOWER_TRANSPORT_TCP
) {
277 rt
->lower_transport
= RTSP_LOWER_TRANSPORT_TCP
;
278 if ((ret
= ff_rtsp_open_transport_ctx(s
, rtsp_st
))) {
279 rtsp_send_reply(s
, RTSP_STATUS_TRANSPORT
, NULL
, request
.seq
);
282 rtsp_st
->interleaved_min
= request
.transports
[0].interleaved_min
;
283 rtsp_st
->interleaved_max
= request
.transports
[0].interleaved_max
;
284 snprintf(responseheaders
, sizeof(responseheaders
), "Transport: "
285 "RTP/AVP/TCP;unicast;mode=receive;interleaved=%d-%d"
286 "\r\n", request
.transports
[0].interleaved_min
,
287 request
.transports
[0].interleaved_max
);
290 ff_url_join(url
, sizeof(url
), "rtp", NULL
, host
, localport
, NULL
);
291 av_dlog(s
, "Opening: %s", url
);
292 ret
= ffurl_open(&rtsp_st
->rtp_handle
, url
, AVIO_FLAG_READ_WRITE
,
293 &s
->interrupt_callback
, NULL
);
296 } while (ret
|| localport
> rt
->rtp_port_max
);
297 if (localport
> rt
->rtp_port_max
) {
298 rtsp_send_reply(s
, RTSP_STATUS_TRANSPORT
, NULL
, request
.seq
);
302 av_dlog(s
, "Listening on: %d",
303 ff_rtp_get_local_rtp_port(rtsp_st
->rtp_handle
));
304 if ((ret
= ff_rtsp_open_transport_ctx(s
, rtsp_st
))) {
305 rtsp_send_reply(s
, RTSP_STATUS_TRANSPORT
, NULL
, request
.seq
);
309 localport
= ff_rtp_get_local_rtp_port(rtsp_st
->rtp_handle
);
310 snprintf(responseheaders
, sizeof(responseheaders
), "Transport: "
311 "RTP/AVP/UDP;unicast;mode=receive;source=%s;"
312 "client_port=%d-%d;server_port=%d-%d\r\n",
313 host
, request
.transports
[0].client_port_min
,
314 request
.transports
[0].client_port_max
, localport
,
318 /* Establish sessionid if not previously set */
319 /* Put this in a function? */
320 /* RFC 2326: session id must be at least 8 digits */
321 while (strlen(rt
->session_id
) < 8)
322 av_strlcatf(rt
->session_id
, 512, "%u", av_get_random_seed());
324 av_strlcatf(responseheaders
, sizeof(responseheaders
), "Session: %s\r\n",
327 rtsp_send_reply(s
, RTSP_STATUS_OK
, responseheaders
, request
.seq
);
329 rt
->state
= RTSP_STATE_PAUSED
;
333 static int rtsp_read_record(AVFormatContext
*s
)
335 RTSPState
*rt
= s
->priv_data
;
336 RTSPMessageHeader request
= { 0 };
338 char responseheaders
[1024];
340 ret
= rtsp_read_request(s
, &request
, "RECORD");
343 ret
= check_sessionid(s
, &request
);
347 snprintf(responseheaders
, sizeof(responseheaders
), "Session: %s\r\n",
349 rtsp_send_reply(s
, RTSP_STATUS_OK
, responseheaders
, request
.seq
);
351 rt
->state
= RTSP_STATE_STREAMING
;
355 static inline int parse_command_line(AVFormatContext
*s
, const char *line
,
356 int linelen
, char *uri
, int urisize
,
357 char *method
, int methodsize
,
358 enum RTSPMethod
*methodcode
)
360 RTSPState
*rt
= s
->priv_data
;
361 const char *linept
, *searchlinept
;
362 linept
= strchr(line
, ' ');
364 av_log(s
, AV_LOG_ERROR
, "Error parsing method string\n");
365 return AVERROR_INVALIDDATA
;
367 if (linept
- line
> methodsize
- 1) {
368 av_log(s
, AV_LOG_ERROR
, "Method string too long\n");
371 memcpy(method
, line
, linept
- line
);
372 method
[linept
- line
] = '\0';
374 if (!strcmp(method
, "ANNOUNCE"))
375 *methodcode
= ANNOUNCE
;
376 else if (!strcmp(method
, "OPTIONS"))
377 *methodcode
= OPTIONS
;
378 else if (!strcmp(method
, "RECORD"))
379 *methodcode
= RECORD
;
380 else if (!strcmp(method
, "SETUP"))
382 else if (!strcmp(method
, "PAUSE"))
384 else if (!strcmp(method
, "TEARDOWN"))
385 *methodcode
= TEARDOWN
;
387 *methodcode
= UNKNOWN
;
388 /* Check method with the state */
389 if (rt
->state
== RTSP_STATE_IDLE
) {
390 if ((*methodcode
!= ANNOUNCE
) && (*methodcode
!= OPTIONS
)) {
391 av_log(s
, AV_LOG_ERROR
, "Unexpected command in Idle State %s\n",
393 return AVERROR_PROTOCOL_NOT_FOUND
;
395 } else if (rt
->state
== RTSP_STATE_PAUSED
) {
396 if ((*methodcode
!= OPTIONS
) && (*methodcode
!= RECORD
)
397 && (*methodcode
!= SETUP
)) {
398 av_log(s
, AV_LOG_ERROR
, "Unexpected command in Paused State %s\n",
400 return AVERROR_PROTOCOL_NOT_FOUND
;
402 } else if (rt
->state
== RTSP_STATE_STREAMING
) {
403 if ((*methodcode
!= PAUSE
) && (*methodcode
!= OPTIONS
)
404 && (*methodcode
!= TEARDOWN
)) {
405 av_log(s
, AV_LOG_ERROR
, "Unexpected command in Streaming State"
407 return AVERROR_PROTOCOL_NOT_FOUND
;
410 av_log(s
, AV_LOG_ERROR
, "Unexpected State [%d]\n", rt
->state
);
414 searchlinept
= strchr(linept
, ' ');
416 av_log(s
, AV_LOG_ERROR
, "Error parsing message URI\n");
417 return AVERROR_INVALIDDATA
;
419 if (searchlinept
- linept
> urisize
- 1) {
420 av_log(s
, AV_LOG_ERROR
, "uri string length exceeded buffer size\n");
423 memcpy(uri
, linept
, searchlinept
- linept
);
424 uri
[searchlinept
- linept
] = '\0';
425 if (strcmp(rt
->control_uri
, uri
)) {
426 char host
[128], path
[512], auth
[128];
428 char ctl_host
[128], ctl_path
[512], ctl_auth
[128];
430 av_url_split(NULL
, 0, auth
, sizeof(auth
), host
, sizeof(host
), &port
,
431 path
, sizeof(path
), uri
);
432 av_url_split(NULL
, 0, ctl_auth
, sizeof(ctl_auth
), ctl_host
,
433 sizeof(ctl_host
), &ctl_port
, ctl_path
, sizeof(ctl_path
),
435 if (strcmp(host
, ctl_host
))
436 av_log(s
, AV_LOG_INFO
, "Host %s differs from expected %s\n",
438 if (strcmp(path
, ctl_path
) && *methodcode
!= SETUP
)
439 av_log(s
, AV_LOG_WARNING
, "WARNING: Path %s differs from expected"
440 " %s\n", path
, ctl_path
);
441 if (*methodcode
== ANNOUNCE
) {
442 av_log(s
, AV_LOG_INFO
,
443 "Updating control URI to %s\n", uri
);
444 av_strlcpy(rt
->control_uri
, uri
, sizeof(rt
->control_uri
));
448 linept
= searchlinept
+ 1;
449 if (!av_strstart(linept
, "RTSP/1.0", NULL
)) {
450 av_log(s
, AV_LOG_ERROR
, "Error parsing protocol or version\n");
451 return AVERROR_PROTOCOL_NOT_FOUND
;
456 int ff_rtsp_parse_streaming_commands(AVFormatContext
*s
)
458 RTSPState
*rt
= s
->priv_data
;
459 unsigned char rbuf
[4096];
460 unsigned char method
[10];
464 RTSPMessageHeader request
= { 0 };
465 enum RTSPMethod methodcode
;
467 ret
= read_line(s
, rbuf
, sizeof(rbuf
), &rbuflen
);
470 ret
= parse_command_line(s
, rbuf
, rbuflen
, uri
, sizeof(uri
), method
,
471 sizeof(method
), &methodcode
);
473 av_log(s
, AV_LOG_ERROR
, "RTSP: Unexpected Command\n");
477 ret
= rtsp_read_request(s
, &request
, method
);
481 if (methodcode
== PAUSE
) {
482 rt
->state
= RTSP_STATE_PAUSED
;
483 ret
= rtsp_send_reply(s
, RTSP_STATUS_OK
, NULL
, request
.seq
);
484 // TODO: Missing date header in response
485 } else if (methodcode
== OPTIONS
) {
486 ret
= rtsp_send_reply(s
, RTSP_STATUS_OK
,
487 "Public: ANNOUNCE, PAUSE, SETUP, TEARDOWN, "
488 "RECORD\r\n", request
.seq
);
489 } else if (methodcode
== TEARDOWN
) {
490 rt
->state
= RTSP_STATE_IDLE
;
491 ret
= rtsp_send_reply(s
, RTSP_STATUS_OK
, NULL
, request
.seq
);
497 static int rtsp_read_play(AVFormatContext
*s
)
499 RTSPState
*rt
= s
->priv_data
;
500 RTSPMessageHeader reply1
, *reply
= &reply1
;
504 av_log(s
, AV_LOG_DEBUG
, "hello state=%d\n", rt
->state
);
507 if (!(rt
->server_type
== RTSP_SERVER_REAL
&& rt
->need_subscription
)) {
508 if (rt
->transport
== RTSP_TRANSPORT_RTP
) {
509 for (i
= 0; i
< rt
->nb_rtsp_streams
; i
++) {
510 RTSPStream
*rtsp_st
= rt
->rtsp_streams
[i
];
511 RTPDemuxContext
*rtpctx
= rtsp_st
->transport_priv
;
514 ff_rtp_reset_packet_queue(rtpctx
);
515 rtpctx
->last_rtcp_ntp_time
= AV_NOPTS_VALUE
;
516 rtpctx
->first_rtcp_ntp_time
= AV_NOPTS_VALUE
;
517 rtpctx
->base_timestamp
= 0;
518 rtpctx
->timestamp
= 0;
519 rtpctx
->unwrapped_timestamp
= 0;
520 rtpctx
->rtcp_ts_offset
= 0;
523 if (rt
->state
== RTSP_STATE_PAUSED
) {
526 snprintf(cmd
, sizeof(cmd
),
527 "Range: npt=%"PRId64
".%03"PRId64
"-\r\n",
528 rt
->seek_timestamp
/ AV_TIME_BASE
,
529 rt
->seek_timestamp
/ (AV_TIME_BASE
/ 1000) % 1000);
531 ff_rtsp_send_cmd(s
, "PLAY", rt
->control_uri
, cmd
, reply
, NULL
);
532 if (reply
->status_code
!= RTSP_STATUS_OK
) {
535 if (rt
->transport
== RTSP_TRANSPORT_RTP
&&
536 reply
->range_start
!= AV_NOPTS_VALUE
) {
537 for (i
= 0; i
< rt
->nb_rtsp_streams
; i
++) {
538 RTSPStream
*rtsp_st
= rt
->rtsp_streams
[i
];
539 RTPDemuxContext
*rtpctx
= rtsp_st
->transport_priv
;
541 if (!rtpctx
|| rtsp_st
->stream_index
< 0)
543 st
= s
->streams
[rtsp_st
->stream_index
];
544 rtpctx
->range_start_offset
=
545 av_rescale_q(reply
->range_start
, AV_TIME_BASE_Q
,
550 rt
->state
= RTSP_STATE_STREAMING
;
554 /* pause the stream */
555 static int rtsp_read_pause(AVFormatContext
*s
)
557 RTSPState
*rt
= s
->priv_data
;
558 RTSPMessageHeader reply1
, *reply
= &reply1
;
560 if (rt
->state
!= RTSP_STATE_STREAMING
)
562 else if (!(rt
->server_type
== RTSP_SERVER_REAL
&& rt
->need_subscription
)) {
563 ff_rtsp_send_cmd(s
, "PAUSE", rt
->control_uri
, NULL
, reply
, NULL
);
564 if (reply
->status_code
!= RTSP_STATUS_OK
) {
568 rt
->state
= RTSP_STATE_PAUSED
;
572 int ff_rtsp_setup_input_streams(AVFormatContext
*s
, RTSPMessageHeader
*reply
)
574 RTSPState
*rt
= s
->priv_data
;
576 unsigned char *content
= NULL
;
579 /* describe the stream */
580 snprintf(cmd
, sizeof(cmd
),
581 "Accept: application/sdp\r\n");
582 if (rt
->server_type
== RTSP_SERVER_REAL
) {
584 * The Require: attribute is needed for proper streaming from
588 "Require: com.real.retain-entity-for-setup\r\n",
591 ff_rtsp_send_cmd(s
, "DESCRIBE", rt
->control_uri
, cmd
, reply
, &content
);
593 return AVERROR_INVALIDDATA
;
594 if (reply
->status_code
!= RTSP_STATUS_OK
) {
596 return AVERROR_INVALIDDATA
;
599 av_log(s
, AV_LOG_VERBOSE
, "SDP:\n%s\n", content
);
600 /* now we got the SDP description, we parse it */
601 ret
= ff_sdp_parse(s
, (const char *)content
);
609 static int rtsp_listen(AVFormatContext
*s
)
611 RTSPState
*rt
= s
->priv_data
;
612 char host
[128], path
[512], auth
[128];
616 unsigned char rbuf
[4096];
617 unsigned char method
[10];
620 enum RTSPMethod methodcode
;
622 /* extract hostname and port */
623 av_url_split(NULL
, 0, auth
, sizeof(auth
), host
, sizeof(host
), &port
,
624 path
, sizeof(path
), s
->filename
);
626 /* ff_url_join. No authorization by now (NULL) */
627 ff_url_join(rt
->control_uri
, sizeof(rt
->control_uri
), "rtsp", NULL
, host
,
631 port
= RTSP_DEFAULT_PORT
;
633 /* Create TCP connection */
634 ff_url_join(tcpname
, sizeof(tcpname
), "tcp", NULL
, host
, port
,
635 "?listen&listen_timeout=%d", rt
->initial_timeout
* 1000);
637 if (ret
= ffurl_open(&rt
->rtsp_hd
, tcpname
, AVIO_FLAG_READ_WRITE
,
638 &s
->interrupt_callback
, NULL
)) {
639 av_log(s
, AV_LOG_ERROR
, "Unable to open RTSP for listening\n");
642 rt
->state
= RTSP_STATE_IDLE
;
643 rt
->rtsp_hd_out
= rt
->rtsp_hd
;
644 for (;;) { /* Wait for incoming RTSP messages */
645 ret
= read_line(s
, rbuf
, sizeof(rbuf
), &rbuflen
);
648 ret
= parse_command_line(s
, rbuf
, rbuflen
, uri
, sizeof(uri
), method
,
649 sizeof(method
), &methodcode
);
651 av_log(s
, AV_LOG_ERROR
, "RTSP: Unexpected Command\n");
655 if (methodcode
== ANNOUNCE
) {
656 ret
= rtsp_read_announce(s
);
657 rt
->state
= RTSP_STATE_PAUSED
;
658 } else if (methodcode
== OPTIONS
) {
659 ret
= rtsp_read_options(s
);
660 } else if (methodcode
== RECORD
) {
661 ret
= rtsp_read_record(s
);
663 return 0; // We are ready for streaming
664 } else if (methodcode
== SETUP
)
665 ret
= rtsp_read_setup(s
, host
, uri
);
667 ffurl_close(rt
->rtsp_hd
);
668 return AVERROR_INVALIDDATA
;
674 static int rtsp_probe(AVProbeData
*p
)
676 if (av_strstart(p
->filename
, "rtsp:", NULL
))
677 return AVPROBE_SCORE_MAX
;
681 static int rtsp_read_header(AVFormatContext
*s
)
683 RTSPState
*rt
= s
->priv_data
;
686 if (rt
->initial_timeout
> 0)
687 rt
->rtsp_flags
|= RTSP_FLAG_LISTEN
;
689 if (rt
->rtsp_flags
& RTSP_FLAG_LISTEN
) {
690 ret
= rtsp_listen(s
);
694 ret
= ff_rtsp_connect(s
);
698 rt
->real_setup_cache
= !s
->nb_streams
? NULL
:
699 av_mallocz_array(s
->nb_streams
, 2 * sizeof(*rt
->real_setup_cache
));
700 if (!rt
->real_setup_cache
&& s
->nb_streams
)
701 return AVERROR(ENOMEM
);
702 rt
->real_setup
= rt
->real_setup_cache
+ s
->nb_streams
;
704 if (rt
->initial_pause
) {
705 /* do not start immediately */
707 if (rtsp_read_play(s
) < 0) {
708 ff_rtsp_close_streams(s
);
709 ff_rtsp_close_connections(s
);
710 return AVERROR_INVALIDDATA
;
718 int ff_rtsp_tcp_read_packet(AVFormatContext
*s
, RTSPStream
**prtsp_st
,
719 uint8_t *buf
, int buf_size
)
721 RTSPState
*rt
= s
->priv_data
;
725 av_dlog(s
, "tcp_read_packet:\n");
728 RTSPMessageHeader reply
;
730 ret
= ff_rtsp_read_reply(s
, &reply
, NULL
, 1, NULL
);
733 if (ret
== 1) /* received '$' */
735 /* XXX: parse message */
736 if (rt
->state
!= RTSP_STATE_STREAMING
)
739 ret
= ffurl_read_complete(rt
->rtsp_hd
, buf
, 3);
743 len
= AV_RB16(buf
+ 1);
744 av_dlog(s
, "id=%d len=%d\n", id
, len
);
745 if (len
> buf_size
|| len
< 8)
748 ret
= ffurl_read_complete(rt
->rtsp_hd
, buf
, len
);
751 if (rt
->transport
== RTSP_TRANSPORT_RDT
&&
752 ff_rdt_parse_header(buf
, len
, &id
, NULL
, NULL
, NULL
, NULL
) < 0)
755 /* find the matching stream */
756 for (i
= 0; i
< rt
->nb_rtsp_streams
; i
++) {
757 rtsp_st
= rt
->rtsp_streams
[i
];
758 if (id
>= rtsp_st
->interleaved_min
&&
759 id
<= rtsp_st
->interleaved_max
)
768 static int resetup_tcp(AVFormatContext
*s
)
770 RTSPState
*rt
= s
->priv_data
;
774 av_url_split(NULL
, 0, NULL
, 0, host
, sizeof(host
), &port
, NULL
, 0,
776 ff_rtsp_undo_setup(s
, 0);
777 return ff_rtsp_make_setup_request(s
, host
, port
, RTSP_LOWER_TRANSPORT_TCP
,
781 static int rtsp_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
783 RTSPState
*rt
= s
->priv_data
;
785 RTSPMessageHeader reply1
, *reply
= &reply1
;
789 if (rt
->server_type
== RTSP_SERVER_REAL
) {
792 for (i
= 0; i
< s
->nb_streams
; i
++)
793 rt
->real_setup
[i
] = s
->streams
[i
]->discard
;
795 if (!rt
->need_subscription
) {
796 if (memcmp (rt
->real_setup
, rt
->real_setup_cache
,
797 sizeof(enum AVDiscard
) * s
->nb_streams
)) {
798 snprintf(cmd
, sizeof(cmd
),
799 "Unsubscribe: %s\r\n",
800 rt
->last_subscription
);
801 ff_rtsp_send_cmd(s
, "SET_PARAMETER", rt
->control_uri
,
803 if (reply
->status_code
!= RTSP_STATUS_OK
)
804 return AVERROR_INVALIDDATA
;
805 rt
->need_subscription
= 1;
809 if (rt
->need_subscription
) {
810 int r
, rule_nr
, first
= 1;
812 memcpy(rt
->real_setup_cache
, rt
->real_setup
,
813 sizeof(enum AVDiscard
) * s
->nb_streams
);
814 rt
->last_subscription
[0] = 0;
816 snprintf(cmd
, sizeof(cmd
),
818 for (i
= 0; i
< rt
->nb_rtsp_streams
; i
++) {
820 for (r
= 0; r
< s
->nb_streams
; r
++) {
821 if (s
->streams
[r
]->id
== i
) {
822 if (s
->streams
[r
]->discard
!= AVDISCARD_ALL
) {
824 av_strlcat(rt
->last_subscription
, ",",
825 sizeof(rt
->last_subscription
));
826 ff_rdt_subscribe_rule(
827 rt
->last_subscription
,
828 sizeof(rt
->last_subscription
), i
, rule_nr
);
835 av_strlcatf(cmd
, sizeof(cmd
), "%s\r\n", rt
->last_subscription
);
836 ff_rtsp_send_cmd(s
, "SET_PARAMETER", rt
->control_uri
,
838 if (reply
->status_code
!= RTSP_STATUS_OK
)
839 return AVERROR_INVALIDDATA
;
840 rt
->need_subscription
= 0;
842 if (rt
->state
== RTSP_STATE_STREAMING
)
847 ret
= ff_rtsp_fetch_packet(s
, pkt
);
849 if (ret
== AVERROR(ETIMEDOUT
) && !rt
->packets
) {
850 if (rt
->lower_transport
== RTSP_LOWER_TRANSPORT_UDP
&&
851 rt
->lower_transport_mask
& (1 << RTSP_LOWER_TRANSPORT_TCP
)) {
852 RTSPMessageHeader reply1
, *reply
= &reply1
;
853 av_log(s
, AV_LOG_WARNING
, "UDP timeout, retrying with TCP\n");
854 if (rtsp_read_pause(s
) != 0)
856 // TEARDOWN is required on Real-RTSP, but might make
857 // other servers close the connection.
858 if (rt
->server_type
== RTSP_SERVER_REAL
)
859 ff_rtsp_send_cmd(s
, "TEARDOWN", rt
->control_uri
, NULL
,
861 rt
->session_id
[0] = '\0';
862 if (resetup_tcp(s
) == 0) {
863 rt
->state
= RTSP_STATE_IDLE
;
864 rt
->need_subscription
= 1;
865 if (rtsp_read_play(s
) != 0)
875 if (!(rt
->rtsp_flags
& RTSP_FLAG_LISTEN
)) {
876 /* send dummy request to keep TCP connection alive */
877 if ((av_gettime() - rt
->last_cmd_time
) / 1000000 >= rt
->timeout
/ 2 ||
878 rt
->auth_state
.stale
) {
879 if (rt
->server_type
== RTSP_SERVER_WMS
||
880 (rt
->server_type
!= RTSP_SERVER_REAL
&&
881 rt
->get_parameter_supported
)) {
882 ff_rtsp_send_cmd_async(s
, "GET_PARAMETER", rt
->control_uri
, NULL
);
884 ff_rtsp_send_cmd_async(s
, "OPTIONS", rt
->control_uri
, NULL
);
886 /* The stale flag should be reset when creating the auth response in
887 * ff_rtsp_send_cmd_async, but reset it here just in case we never
888 * called the auth code (if we didn't have any credentials set). */
889 rt
->auth_state
.stale
= 0;
896 static int rtsp_read_seek(AVFormatContext
*s
, int stream_index
,
897 int64_t timestamp
, int flags
)
899 RTSPState
*rt
= s
->priv_data
;
901 rt
->seek_timestamp
= av_rescale_q(timestamp
,
902 s
->streams
[stream_index
]->time_base
,
906 case RTSP_STATE_IDLE
:
908 case RTSP_STATE_STREAMING
:
909 if (rtsp_read_pause(s
) != 0)
911 rt
->state
= RTSP_STATE_SEEKING
;
912 if (rtsp_read_play(s
) != 0)
915 case RTSP_STATE_PAUSED
:
916 rt
->state
= RTSP_STATE_IDLE
;
922 static const AVClass rtsp_demuxer_class
= {
923 .class_name
= "RTSP demuxer",
924 .item_name
= av_default_item_name
,
925 .option
= ff_rtsp_options
,
926 .version
= LIBAVUTIL_VERSION_INT
,
929 AVInputFormat ff_rtsp_demuxer
= {
931 .long_name
= NULL_IF_CONFIG_SMALL("RTSP input"),
932 .priv_data_size
= sizeof(RTSPState
),
933 .read_probe
= rtsp_probe
,
934 .read_header
= rtsp_read_header
,
935 .read_packet
= rtsp_read_packet
,
936 .read_close
= rtsp_read_close
,
937 .read_seek
= rtsp_read_seek
,
938 .flags
= AVFMT_NOFILE
,
939 .read_play
= rtsp_read_play
,
940 .read_pause
= rtsp_read_pause
,
941 .priv_class
= &rtsp_demuxer_class
,