#include "libavutil/intreadwrite.h"
#include "libavutil/mathematics.h"
#include "libavutil/random_seed.h"
+#include "libavutil/time.h"
#include "avformat.h"
#include "internal.h"
#include "network.h"
#include "os_support.h"
+#include "rtpproto.h"
#include "rtsp.h"
#include "rdt.h"
#include "url.h"
do {
ret = ffurl_read_complete(rt->rtsp_hd, rbuf + idx, 1);
- if (ret < 0)
- return ret;
+ if (ret <= 0)
+ return ret ? ret : AVERROR_EOF;
if (rbuf[idx] == '\r') {
/* Ignore */
} else if (rbuf[idx] == '\n') {
av_strlcat(message, extracontent, sizeof(message));
av_strlcat(message, "\r\n", sizeof(message));
av_dlog(s, "Sending response:\n%s", message);
- ffurl_write(rt->rtsp_hd, message, strlen(message));
+ ffurl_write(rt->rtsp_hd_out, message, strlen(message));
return 0;
}
RTSPState *rt = s->priv_data;
const char *linept, *searchlinept;
linept = strchr(line, ' ');
+
+ if (!linept)
+ return AVERROR_INVALIDDATA;
+
if (linept - line > methodsize - 1) {
av_log(s, AV_LOG_ERROR, "Method string too long\n");
return AVERROR(EIO);
}
searchlinept = strchr(linept, ' ');
- if (searchlinept == NULL) {
+ if (!searchlinept) {
av_log(s, AV_LOG_ERROR, "Error parsing message URI\n");
return AVERROR_INVALIDDATA;
}
if (*methodcode == ANNOUNCE) {
av_log(s, AV_LOG_INFO,
"Updating control URI to %s\n", uri);
- strcpy(rt->control_uri, uri);
+ av_strlcpy(rt->control_uri, uri, sizeof(rt->control_uri));
}
}
av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state);
rt->nb_byes = 0;
+ if (rt->lower_transport == RTSP_LOWER_TRANSPORT_UDP) {
+ for (i = 0; i < rt->nb_rtsp_streams; i++) {
+ RTSPStream *rtsp_st = rt->rtsp_streams[i];
+ /* Try to initialize the connection state in a
+ * potential NAT router by sending dummy packets.
+ * RTP/RTCP dummy packets are used for RDT, too.
+ */
+ if (rtsp_st->rtp_handle &&
+ !(rt->server_type == RTSP_SERVER_WMS && i > 1))
+ ff_rtp_send_punch_packets(rtsp_st->rtp_handle);
+ }
+ }
if (!(rt->server_type == RTSP_SERVER_REAL && rt->need_subscription)) {
if (rt->transport == RTSP_TRANSPORT_RTP) {
for (i = 0; i < rt->nb_rtsp_streams; i++) {
static int rtsp_listen(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
- char host[128], path[512], auth[128];
+ char proto[128], host[128], path[512], auth[128];
char uri[500];
int port;
+ int default_port = RTSP_DEFAULT_PORT;
char tcpname[500];
+ const char *lower_proto = "tcp";
unsigned char rbuf[4096];
unsigned char method[10];
int rbuflen = 0;
enum RTSPMethod methodcode;
/* extract hostname and port */
- av_url_split(NULL, 0, auth, sizeof(auth), host, sizeof(host), &port,
- path, sizeof(path), s->filename);
+ av_url_split(proto, sizeof(proto), auth, sizeof(auth), host, sizeof(host),
+ &port, path, sizeof(path), s->filename);
/* ff_url_join. No authorization by now (NULL) */
- ff_url_join(rt->control_uri, sizeof(rt->control_uri), "rtsp", NULL, host,
+ ff_url_join(rt->control_uri, sizeof(rt->control_uri), proto, NULL, host,
port, "%s", path);
+
+ if (!strcmp(proto, "rtsps")) {
+ lower_proto = "tls";
+ default_port = RTSPS_DEFAULT_PORT;
+ }
+
+ if (port < 0)
+ port = default_port;
+
/* Create TCP connection */
- ff_url_join(tcpname, sizeof(tcpname), "tcp", NULL, host, port,
+ ff_url_join(tcpname, sizeof(tcpname), lower_proto, NULL, host, port,
"?listen&listen_timeout=%d", rt->initial_timeout * 1000);
if (ret = ffurl_open(&rt->rtsp_hd, tcpname, AVIO_FLAG_READ_WRITE,
static int rtsp_probe(AVProbeData *p)
{
- if (av_strstart(p->filename, "rtsp:", NULL))
+ if (
+#if CONFIG_TLS_PROTOCOL
+ av_strstart(p->filename, "rtsps:", NULL) ||
+#endif
+ av_strstart(p->filename, "rtsp:", NULL))
return AVPROBE_SCORE_MAX;
return 0;
}
av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0,
s->filename);
- ff_rtsp_undo_setup(s);
+ ff_rtsp_undo_setup(s, 0);
return ff_rtsp_make_setup_request(s, host, port, RTSP_LOWER_TRANSPORT_TCP,
rt->real_challenge);
}
if (!(rt->rtsp_flags & RTSP_FLAG_LISTEN)) {
/* send dummy request to keep TCP connection alive */
- if ((av_gettime() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2 ||
+ if ((av_gettime_relative() - rt->last_cmd_time) / 1000000 >= rt->timeout / 2 ||
rt->auth_state.stale) {
if (rt->server_type == RTSP_SERVER_WMS ||
(rt->server_type != RTSP_SERVER_REAL &&
rt->get_parameter_supported)) {
ff_rtsp_send_cmd_async(s, "GET_PARAMETER", rt->control_uri, NULL);
} else {
- ff_rtsp_send_cmd_async(s, "OPTIONS", "*", NULL);
+ ff_rtsp_send_cmd_async(s, "OPTIONS", rt->control_uri, NULL);
}
/* The stale flag should be reset when creating the auth response in
* ff_rtsp_send_cmd_async, but reset it here just in case we never
AVInputFormat ff_rtsp_demuxer = {
.name = "rtsp",
- .long_name = NULL_IF_CONFIG_SMALL("RTSP input format"),
+ .long_name = NULL_IF_CONFIG_SMALL("RTSP input"),
.priv_data_size = sizeof(RTSPState),
.read_probe = rtsp_probe,
.read_header = rtsp_read_header,