|
|
|
@@ -900,9 +900,13 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply, |
|
|
|
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) */ |
|
|
|
@@ -938,9 +942,15 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply, |
|
|
|
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)); |
|
|
|
@@ -949,7 +959,7 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *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; |
|
|
|
@@ -964,6 +974,44 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply, |
|
|
|
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 reciving, 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); |
|
|
|
|