#include "network.h"
#include "rtsp.h"
-#include "rtp.h"
+#include "rtpdec.h"
#include "rdt.h"
//#define DEBUG
if (payload_type >= RTP_PT_PRIVATE) {
RTPDynamicProtocolHandler *handler= RTPFirstDynamicPayloadHandler;
while(handler) {
- if (!strcmp(buf, handler->enc_name) && (codec->codec_type == handler->codec_type)) {
+ if (!strcasecmp(buf, handler->enc_name) && (codec->codec_type == handler->codec_type)) {
codec->codec_id = handler->codec_id;
rtsp_st->dynamic_handler= handler;
if(handler->open) {
}
break;
case 's':
- av_strlcpy(s->title, p, sizeof(s->title));
+ av_metadata_set(&s->metadata, "title", p);
break;
case 'i':
if (s->nb_streams == 0) {
- av_strlcpy(s->comment, p, sizeof(s->comment));
+ av_metadata_set(&s->metadata, "comment", p);
break;
}
break;
codec_type = CODEC_TYPE_AUDIO;
} else if (!strcmp(st_type, "video")) {
codec_type = CODEC_TYPE_VIDEO;
+ } else if (!strcmp(st_type, "application")) {
+ codec_type = CODEC_TYPE_DATA;
} else {
s1->skip_media = 1;
return;
st->codec->codec_type = codec_type;
if (rtsp_st->sdp_payload_type < RTP_PT_PRIVATE) {
/* if standard payload type, we can find the codec right now */
- rtp_get_codec_info(st->codec, rtsp_st->sdp_payload_type);
+ ff_rtp_get_codec_info(st->codec, rtsp_st->sdp_payload_type);
}
}
/* put a default control url */
}
/* XXX: only one transport specification is parsed */
-static void rtsp_parse_transport(RTSPHeader *reply, const char *p)
+static void rtsp_parse_transport(RTSPMessageHeader *reply, const char *p)
{
char transport_protocol[16];
char profile[16];
}
}
-void rtsp_parse_line(RTSPHeader *reply, const char *buf)
+void rtsp_parse_line(RTSPMessageHeader *reply, const char *buf)
{
const char *p;
}
}
-static void rtsp_send_cmd(AVFormatContext *s,
- const char *cmd, RTSPHeader *reply,
- unsigned char **content_ptr)
+static void
+rtsp_read_reply (AVFormatContext *s, RTSPMessageHeader *reply,
+ unsigned char **content_ptr)
{
RTSPState *rt = s->priv_data;
char buf[4096], buf1[1024], *q;
unsigned char ch;
const char *p;
- int content_length, line_count;
+ int content_length, line_count = 0;
unsigned char *content = NULL;
- memset(reply, 0, sizeof(RTSPHeader));
-
- rt->seq++;
- av_strlcpy(buf, cmd, sizeof(buf));
- snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq);
- av_strlcat(buf, buf1, sizeof(buf));
- if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) {
- snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id);
- av_strlcat(buf, buf1, sizeof(buf));
- }
- av_strlcat(buf, "\r\n", sizeof(buf));
-#ifdef DEBUG
- printf("Sending:\n%s--\n", buf);
-#endif
- url_write(rt->rtsp_hd, buf, strlen(buf));
+ memset(reply, 0, sizeof(*reply));
/* parse reply (XXX: use buffers) */
- line_count = 0;
rt->last_reply[0] = '\0';
for(;;) {
q = buf;
av_free(content);
}
+static void rtsp_send_cmd(AVFormatContext *s,
+ const char *cmd, RTSPMessageHeader *reply,
+ unsigned char **content_ptr)
+{
+ RTSPState *rt = s->priv_data;
+ char buf[4096], buf1[1024];
+
+ rt->seq++;
+ av_strlcpy(buf, cmd, sizeof(buf));
+ snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq);
+ av_strlcat(buf, buf1, sizeof(buf));
+ if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) {
+ snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id);
+ av_strlcat(buf, buf1, sizeof(buf));
+ }
+ av_strlcat(buf, "\r\n", sizeof(buf));
+#ifdef DEBUG
+ printf("Sending:\n%s--\n", buf);
+#endif
+ url_write(rt->rtsp_hd, buf, strlen(buf));
+
+ rtsp_read_reply(s, reply, content_ptr);
+}
+
/* close and free RTSP streams */
static void rtsp_close_streams(RTSPState *rt)
for(i=0;i<rt->nb_rtsp_streams;i++) {
rtsp_st = rt->rtsp_streams[i];
if (rtsp_st) {
- if (rtsp_st->tx_ctx) {
+ if (rtsp_st->transport_priv) {
if (rt->transport == RTSP_TRANSPORT_RDT)
- ff_rdt_parse_close(rtsp_st->tx_ctx);
+ ff_rdt_parse_close(rtsp_st->transport_priv);
else
- rtp_parse_close(rtsp_st->tx_ctx);
+ rtp_parse_close(rtsp_st->transport_priv);
}
if (rtsp_st->rtp_handle)
url_close(rtsp_st->rtp_handle);
s->ctx_flags |= AVFMTCTX_NOHEADER;
if (rt->transport == RTSP_TRANSPORT_RDT)
- rtsp_st->tx_ctx = ff_rdt_parse_open(s, st->index,
+ rtsp_st->transport_priv = ff_rdt_parse_open(s, st->index,
rtsp_st->dynamic_protocol_context,
rtsp_st->dynamic_handler);
else
- rtsp_st->tx_ctx = rtp_parse_open(s, st, rtsp_st->rtp_handle,
+ rtsp_st->transport_priv = rtp_parse_open(s, st, rtsp_st->rtp_handle,
rtsp_st->sdp_payload_type,
&rtsp_st->rtp_payload_data);
- if (!rtsp_st->tx_ctx) {
+ if (!rtsp_st->transport_priv) {
return AVERROR(ENOMEM);
} else if (rt->transport != RTSP_TRANSPORT_RDT) {
if(rtsp_st->dynamic_handler) {
- rtp_parse_set_dynamic_protocol(rtsp_st->tx_ctx,
+ rtp_parse_set_dynamic_protocol(rtsp_st->transport_priv,
rtsp_st->dynamic_protocol_context,
rtsp_st->dynamic_handler);
}
int lower_transport, const char *real_challenge)
{
RTSPState *rt = s->priv_data;
- int j, i, err;
+ int rtx, j, i, err, interleave = 0;
RTSPStream *rtsp_st;
- RTSPHeader reply1, *reply = &reply1;
+ RTSPMessageHeader reply1, *reply = &reply1;
char cmd[2048];
const char *trans_pref;
for(j = RTSP_RTP_PORT_MIN, i = 0; i < rt->nb_rtsp_streams; ++i) {
char transport[2048];
- rtsp_st = rt->rtsp_streams[i];
+ /**
+ * WMS serves all UDP data over a single connection, the RTX, which
+ * isn't necessarily the first in the SDP but has to be the first
+ * to be set up, else the second/third SETUP will fail with a 461.
+ */
+ if (lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
+ rt->server_type == RTSP_SERVER_WMS) {
+ if (i == 0) {
+ /* rtx first */
+ for (rtx = 0; rtx < rt->nb_rtsp_streams; rtx++) {
+ int len = strlen(rt->rtsp_streams[rtx]->control_url);
+ if (len >= 4 &&
+ !strcmp(rt->rtsp_streams[rtx]->control_url + len - 4, "/rtx"))
+ break;
+ }
+ if (rtx == rt->nb_rtsp_streams)
+ return -1; /* no RTX found */
+ rtsp_st = rt->rtsp_streams[rtx];
+ } else
+ rtsp_st = rt->rtsp_streams[i > rtx ? i : i - 1];
+ } else
+ rtsp_st = rt->rtsp_streams[i];
/* RTP/UDP */
if (lower_transport == RTSP_LOWER_TRANSPORT_UDP) {
char buf[256];
+ if (rt->server_type == RTSP_SERVER_WMS && i > 1) {
+ port = reply->transports[0].client_port_min;
+ goto have_port;
+ }
+
/* first try in specified port range */
if (RTSP_RTP_PORT_MIN != 0) {
while(j <= RTSP_RTP_PORT_MAX) {
rtp_opened:
port = rtp_get_local_port(rtsp_st->rtp_handle);
+ have_port:
snprintf(transport, sizeof(transport) - 1,
"%s/UDP;", trans_pref);
if (rt->server_type != RTSP_SERVER_REAL)
av_strlcat(transport, "unicast;", sizeof(transport));
av_strlcatf(transport, sizeof(transport),
"client_port=%d", port);
- if (rt->transport == RTSP_TRANSPORT_RTP)
+ if (rt->transport == RTSP_TRANSPORT_RTP &&
+ !(rt->server_type == RTSP_SERVER_WMS && i > 0))
av_strlcatf(transport, sizeof(transport), "-%d", port + 1);
}
/* RTP/TCP */
else if (lower_transport == RTSP_LOWER_TRANSPORT_TCP) {
+ /** For WMS streams, the application streams are only used for
+ * UDP. When trying to set it up for TCP streams, the server
+ * will return an error. Therefore, we skip those streams. */
+ if (rt->server_type == RTSP_SERVER_WMS &&
+ s->streams[rtsp_st->stream_index]->codec->codec_type == CODEC_TYPE_DATA)
+ continue;
snprintf(transport, sizeof(transport) - 1,
- "%s/TCP", trans_pref);
+ "%s/TCP;", trans_pref);
+ if (rt->server_type == RTSP_SERVER_WMS)
+ av_strlcat(transport, "unicast;", sizeof(transport));
+ av_strlcatf(transport, sizeof(transport),
+ "interleaved=%d-%d",
+ interleave, interleave + 1);
+ interleave += 2;
}
else if (lower_transport == RTSP_LOWER_TRANSPORT_UDP_MULTICAST) {
snprintf(transport, sizeof(transport) - 1,
"%s/UDP;multicast", trans_pref);
}
- if (rt->server_type == RTSP_SERVER_REAL)
+ if (rt->server_type == RTSP_SERVER_REAL ||
+ rt->server_type == RTSP_SERVER_WMS)
av_strlcat(transport, ";mode=play", sizeof(transport));
snprintf(cmd, sizeof(cmd),
"SETUP %s RTSP/1.0\r\n"
/* XXX: also use address if specified */
snprintf(url, sizeof(url), "rtp://%s:%d",
host, reply->transports[0].server_port_min);
- if (rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {
+ if (!(rt->server_type == RTSP_SERVER_WMS && i > 1) &&
+ rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {
err = AVERROR_INVALIDDATA;
goto fail;
}
char host[1024], path[1024], tcpname[1024], cmd[2048], *option_list, *option;
URLContext *rtsp_hd;
int port, ret, err;
- RTSPHeader reply1, *reply = &reply1;
+ RTSPMessageHeader reply1, *reply = &reply1;
unsigned char *content = NULL;
int lower_transport_mask = 0;
char real_challenge[64];
}
if (!lower_transport_mask)
- lower_transport_mask = (1 << RTSP_LOWER_TRANSPORT_LAST) - 1;
+ lower_transport_mask = (1 << RTSP_LOWER_TRANSPORT_NB) - 1;
/* open the tcp connexion */
snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port);
RTSPState *rt = s->priv_data;
RTSPStream *rtsp_st;
fd_set rfds;
- int fd1, fd2, fd_max, n, i, ret;
+ int fd, fd_max, n, i, ret;
struct timeval tv;
for(;;) {
fd_max = -1;
for(i = 0; i < rt->nb_rtsp_streams; i++) {
rtsp_st = rt->rtsp_streams[i];
- /* currently, we cannot probe RTCP handle because of blocking restrictions */
- rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2);
- if (fd1 > fd_max)
- fd_max = fd1;
- FD_SET(fd1, &rfds);
+ if (rtsp_st->rtp_handle) {
+ /* currently, we cannot probe RTCP handle because of
+ * blocking restrictions */
+ fd = url_get_file_handle(rtsp_st->rtp_handle);
+ if (fd > fd_max)
+ fd_max = fd;
+ FD_SET(fd, &rfds);
+ }
}
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
if (n > 0) {
for(i = 0; i < rt->nb_rtsp_streams; i++) {
rtsp_st = rt->rtsp_streams[i];
- rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2);
- if (FD_ISSET(fd1, &rfds)) {
- ret = url_read(rtsp_st->rtp_handle, buf, buf_size);
- if (ret > 0) {
- *prtsp_st = rtsp_st;
- return ret;
+ if (rtsp_st->rtp_handle) {
+ fd = url_get_file_handle(rtsp_st->rtp_handle);
+ if (FD_ISSET(fd, &rfds)) {
+ ret = url_read(rtsp_st->rtp_handle, buf, buf_size);
+ if (ret > 0) {
+ *prtsp_st = rtsp_st;
+ return ret;
+ }
}
}
}
if (rt->server_type == RTSP_SERVER_REAL) {
int i;
- RTSPHeader reply1, *reply = &reply1;
+ RTSPMessageHeader reply1, *reply = &reply1;
enum AVDiscard cache[MAX_STREAMS];
char cmd[1024];
}
/* get next frames from the same RTP packet */
- if (rt->cur_tx) {
+ if (rt->cur_transport_priv) {
if (rt->transport == RTSP_TRANSPORT_RDT)
- ret = ff_rdt_parse_packet(rt->cur_tx, pkt, NULL, 0);
+ ret = ff_rdt_parse_packet(rt->cur_transport_priv, pkt, NULL, 0);
else
- ret = rtp_parse_packet(rt->cur_tx, pkt, NULL, 0);
+ ret = rtp_parse_packet(rt->cur_transport_priv, pkt, NULL, 0);
if (ret == 0) {
- rt->cur_tx = NULL;
+ rt->cur_transport_priv = NULL;
return 0;
} else if (ret == 1) {
return 0;
} else {
- rt->cur_tx = NULL;
+ rt->cur_transport_priv = NULL;
}
}
case RTSP_LOWER_TRANSPORT_UDP:
case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
len = udp_read_packet(s, &rtsp_st, buf, sizeof(buf));
- if (len >=0 && rtsp_st->tx_ctx && rt->transport == RTSP_TRANSPORT_RTP)
- rtp_check_and_send_back_rr(rtsp_st->tx_ctx, len);
+ if (len >=0 && rtsp_st->transport_priv && rt->transport == RTSP_TRANSPORT_RTP)
+ rtp_check_and_send_back_rr(rtsp_st->transport_priv, len);
break;
}
if (len < 0)
return len;
if (rt->transport == RTSP_TRANSPORT_RDT)
- ret = ff_rdt_parse_packet(rtsp_st->tx_ctx, pkt, buf, len);
+ ret = ff_rdt_parse_packet(rtsp_st->transport_priv, pkt, buf, len);
else
- ret = rtp_parse_packet(rtsp_st->tx_ctx, pkt, buf, len);
+ ret = rtp_parse_packet(rtsp_st->transport_priv, pkt, buf, len);
if (ret < 0)
goto redo;
if (ret == 1) {
/* more packets may follow, so we save the RTP context */
- rt->cur_tx = rtsp_st->tx_ctx;
+ rt->cur_transport_priv = rtsp_st->transport_priv;
}
return 0;
}
static int rtsp_read_play(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
- RTSPHeader reply1, *reply = &reply1;
+ RTSPMessageHeader reply1, *reply = &reply1;
char cmd[1024];
av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state);
static int rtsp_read_pause(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
- RTSPHeader reply1, *reply = &reply1;
+ RTSPMessageHeader reply1, *reply = &reply1;
char cmd[1024];
rt = s->priv_data;
static int rtsp_read_close(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
- RTSPHeader reply1, *reply = &reply1;
+ RTSPMessageHeader reply1, *reply = &reply1;
char cmd[1024];
#if 0