const AVOption ff_rtsp_options[] = {
{ "initial_pause", "Don't start playing the stream immediately", OFFSET(initial_pause), AV_OPT_TYPE_INT, {0}, 0, 1, DEC },
- FF_RTP_FLAG_OPTS(RTSPState, rtp_muxer_flags),
+ FF_RTP_FLAG_OPTS(RTSPState, rtp_muxer_flags)
{ "rtsp_transport", "RTSP transport protocols", OFFSET(lower_transport_mask), AV_OPT_TYPE_FLAGS, {0}, INT_MIN, INT_MAX, DEC|ENC, "rtsp_transport" }, \
{ "udp", "UDP", 0, AV_OPT_TYPE_CONST, {1 << RTSP_LOWER_TRANSPORT_UDP}, 0, 0, DEC|ENC, "rtsp_transport" }, \
{ "tcp", "TCP", 0, AV_OPT_TYPE_CONST, {1 << RTSP_LOWER_TRANSPORT_TCP}, 0, 0, DEC|ENC, "rtsp_transport" }, \
char buf[4096], buf1[1024], *q;
unsigned char ch;
const char *p;
- int ret, content_length, line_count = 0;
+ int ret, content_length, line_count = 0, request = 0;
unsigned char *content = NULL;
+start:
+ line_count = 0;
+ request = 0;
+ content = NULL;
memset(reply, 0, sizeof(*reply));
/* parse reply (XXX: use buffers) */
if (line_count == 0) {
/* get reply code */
get_word(buf1, sizeof(buf1), &p);
- get_word(buf1, sizeof(buf1), &p);
- reply->status_code = atoi(buf1);
- av_strlcpy(reply->reason, p, sizeof(reply->reason));
+ if (!strncmp(buf1, "RTSP/", 5)) {
+ get_word(buf1, sizeof(buf1), &p);
+ reply->status_code = atoi(buf1);
+ av_strlcpy(reply->reason, p, sizeof(reply->reason));
+ } else {
+ av_strlcpy(reply->reason, buf1, sizeof(reply->reason)); // method
+ get_word(buf1, sizeof(buf1), &p); // object
+ request = 1;
+ }
} else {
ff_rtsp_parse_line(reply, p, rt, method);
av_strlcat(rt->last_reply, p, sizeof(rt->last_reply));
line_count++;
}
- if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0')
+ if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0' && !request)
av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id));
content_length = reply->content_length;
else
av_free(content);
+ if (request) {
+ char buf[1024];
+ char base64buf[AV_BASE64_SIZE(sizeof(buf))];
+ const char* ptr = buf;
+
+ if (!strcmp(reply->reason, "OPTIONS")) {
+ snprintf(buf, sizeof(buf), "RTSP/1.0 200 OK\r\n");
+ if (reply->seq)
+ av_strlcatf(buf, sizeof(buf), "CSeq: %d\r\n", reply->seq);
+ if (reply->session_id[0])
+ av_strlcatf(buf, sizeof(buf), "Session: %s\r\n",
+ reply->session_id);
+ } else {
+ snprintf(buf, sizeof(buf), "RTSP/1.0 501 Not Implemented\r\n");
+ }
+ av_strlcat(buf, "\r\n", sizeof(buf));
+
+ if (rt->control_transport == RTSP_MODE_TUNNEL) {
+ av_base64_encode(base64buf, sizeof(base64buf), buf, strlen(buf));
+ ptr = base64buf;
+ }
+ ffurl_write(rt->rtsp_hd_out, ptr, strlen(ptr));
+
+ rt->last_cmd_time = av_gettime();
+ /* Even if the request from the server had data, it is not the data
+ * that the caller wants or expects. The memory could also be leaked
+ * if the actual following reply has content data. */
+ if (content_ptr)
+ av_freep(content_ptr);
+ /* If method is set, this is called from ff_rtsp_send_cmd,
+ * where a reply to exactly this request is awaited. For
+ * callers from within packet receiving, we just want to
+ * return to the caller and go back to receiving packets. */
+ if (method)
+ goto start;
+ return 0;
+ }
+
if (rt->seq != reply->seq) {
av_log(s, AV_LOG_WARNING, "CSeq %d expected, %d received.\n",
rt->seq, reply->seq);
{
RTSPState *rt = s->priv_data;
HTTPAuthType cur_auth_type;
- int ret;
+ int ret, attempts = 0;
retry:
cur_auth_type = rt->auth_state.auth_type;
if ((ret = ff_rtsp_read_reply(s, reply, content_ptr, 0, method) ) < 0)
return ret;
+ attempts++;
- if (reply->status_code == 401 && cur_auth_type == HTTP_AUTH_NONE &&
- rt->auth_state.auth_type != HTTP_AUTH_NONE)
+ if (reply->status_code == 401 &&
+ (cur_auth_type == HTTP_AUTH_NONE || rt->auth_state.stale) &&
+ rt->auth_state.auth_type != HTTP_AUTH_NONE && attempts < 2)
goto retry;
if (reply->status_code > 400){
break;
}
case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: {
- char url[1024], namebuf[50];
+ char url[1024], namebuf[50], optbuf[20] = "";
struct sockaddr_storage addr;
int port, ttl;
port = rtsp_st->sdp_port;
ttl = rtsp_st->sdp_ttl;
}
+ if (ttl > 0)
+ snprintf(optbuf, sizeof(optbuf), "?ttl=%d", ttl);
getnameinfo((struct sockaddr*) &addr, sizeof(addr),
namebuf, sizeof(namebuf), NULL, 0, NI_NUMERICHOST);
ff_url_join(url, sizeof(url), "rtp", NULL, namebuf,
- port, "?ttl=%d", ttl);
+ port, "%s", optbuf);
if (ffurl_open(&rtsp_st->rtp_handle, url, AVIO_FLAG_READ_WRITE,
&s->interrupt_callback, NULL) < 0) {
err = AVERROR_INVALIDDATA;
continue;
}
+ if (RTP_PT_IS_RTCP(recvbuf[1]))
+ continue;
+
payload_type = recvbuf[1] & 0x7f;
break;
}