📄 rtsp.c
字号:
int content_length, line_count;
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));
/* parse reply (XXX: use buffers) */
line_count = 0;
rt->last_reply[0] = '\0';
for(;;) {
q = buf;
for(;;) {
if (url_readbuf(rt->rtsp_hd, &ch, 1) != 1)
break;
if (ch == '\n')
break;
if (ch == '$') {
/* XXX: only parse it if first char on line ? */
rtsp_skip_packet(s);
} else if (ch != '\r') {
if ((q - buf) < sizeof(buf) - 1)
*q++ = ch;
}
}
*q = '\0';
#ifdef DEBUG
printf("line='%s'\n", buf);
#endif
/* test if last line */
if (buf[0] == '\0')
break;
p = buf;
if (line_count == 0) {
/* get reply code */
get_word(buf1, sizeof(buf1), &p);
get_word(buf1, sizeof(buf1), &p);
reply->status_code = atoi(buf1);
} else {
rtsp_parse_line(reply, p);
av_strlcat(rt->last_reply, p, sizeof(rt->last_reply));
av_strlcat(rt->last_reply, "\n", sizeof(rt->last_reply));
}
line_count++;
}
if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0')
av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id));
content_length = reply->content_length;
if (content_length > 0) {
/* leave some room for a trailing '\0' (useful for simple parsing) */
content = av_malloc(content_length + 1);
(void)url_readbuf(rt->rtsp_hd, content, content_length);
content[content_length] = '\0';
}
if (content_ptr)
*content_ptr = content;
else
av_free(content);
}
/* close and free RTSP streams */
static void rtsp_close_streams(RTSPState *rt)
{
int i;
RTSPStream *rtsp_st;
for(i=0;i<rt->nb_rtsp_streams;i++) {
rtsp_st = rt->rtsp_streams[i];
if (rtsp_st) {
if (rtsp_st->rtp_ctx)
rtp_parse_close(rtsp_st->rtp_ctx);
if (rtsp_st->rtp_handle)
url_close(rtsp_st->rtp_handle);
if (rtsp_st->dynamic_handler && rtsp_st->dynamic_protocol_context)
rtsp_st->dynamic_handler->close(rtsp_st->dynamic_protocol_context);
}
av_free(rtsp_st);
}
av_free(rt->rtsp_streams);
}
static int rtsp_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
RTSPState *rt = s->priv_data;
char host[1024], path[1024], tcpname[1024], cmd[2048], *option_list, *option;
URLContext *rtsp_hd;
int port, i, j, ret, err;
RTSPHeader reply1, *reply = &reply1;
unsigned char *content = NULL;
RTSPStream *rtsp_st;
int protocol_mask = 0;
AVStream *st;
/* extract hostname and port */
url_split(NULL, 0, NULL, 0,
host, sizeof(host), &port, path, sizeof(path), s->filename);
if (port < 0)
port = RTSP_DEFAULT_PORT;
/* search for options */
option_list = strchr(path, '?');
if (option_list) {
/* remove the options from the path */
*option_list++ = 0;
while(option_list) {
/* move the option pointer */
option = option_list;
option_list = strchr(option_list, '&');
if (option_list)
*(option_list++) = 0;
/* handle the options */
if (strcmp(option, "udp") == 0)
protocol_mask = (1<< RTSP_PROTOCOL_RTP_UDP);
else if (strcmp(option, "multicast") == 0)
protocol_mask = (1<< RTSP_PROTOCOL_RTP_UDP_MULTICAST);
else if (strcmp(option, "tcp") == 0)
protocol_mask = (1<< RTSP_PROTOCOL_RTP_TCP);
}
}
if (!protocol_mask)
protocol_mask = rtsp_default_protocols;
/* open the tcp connexion */
snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port);
if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0)
return AVERROR(EIO);
rt->rtsp_hd = rtsp_hd;
rt->seq = 0;
/* describe the stream */
snprintf(cmd, sizeof(cmd),
"DESCRIBE %s RTSP/1.0\r\n"
"Accept: application/sdp\r\n",
s->filename);
rtsp_send_cmd(s, cmd, reply, &content);
if (!content) {
err = AVERROR_INVALIDDATA;
goto fail;
}
if (reply->status_code != RTSP_STATUS_OK) {
err = AVERROR_INVALIDDATA;
goto fail;
}
/* now we got the SDP description, we parse it */
ret = sdp_parse(s, (const char *)content);
av_freep(&content);
if (ret < 0) {
err = AVERROR_INVALIDDATA;
goto fail;
}
/* for each stream, make the setup request */
/* XXX: we assume the same server is used for the control of each
RTSP stream */
for(j = RTSP_RTP_PORT_MIN, i = 0; i < rt->nb_rtsp_streams; ++i) {
char transport[2048];
rtsp_st = rt->rtsp_streams[i];
/* compute available transports */
transport[0] = '\0';
/* RTP/UDP */
if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP)) {
char buf[256];
/* first try in specified port range */
if (RTSP_RTP_PORT_MIN != 0) {
while(j <= RTSP_RTP_PORT_MAX) {
snprintf(buf, sizeof(buf), "rtp://?localport=%d", j);
if (url_open(&rtsp_st->rtp_handle, buf, URL_RDWR) == 0) {
j += 2; /* we will use two port by rtp stream (rtp and rtcp) */
goto rtp_opened;
}
}
}
/* then try on any port
** if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) {
** err = AVERROR_INVALIDDATA;
** goto fail;
** }
*/
rtp_opened:
port = rtp_get_local_port(rtsp_st->rtp_handle);
if (transport[0] != '\0')
av_strlcat(transport, ",", sizeof(transport));
snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1,
"RTP/AVP/UDP;unicast;client_port=%d-%d",
port, port + 1);
}
/* RTP/TCP */
else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_TCP)) {
if (transport[0] != '\0')
av_strlcat(transport, ",", sizeof(transport));
snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1,
"RTP/AVP/TCP");
}
else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST)) {
if (transport[0] != '\0')
av_strlcat(transport, ",", sizeof(transport));
snprintf(transport + strlen(transport),
sizeof(transport) - strlen(transport) - 1,
"RTP/AVP/UDP;multicast");
}
snprintf(cmd, sizeof(cmd),
"SETUP %s RTSP/1.0\r\n"
"Transport: %s\r\n",
rtsp_st->control_url, transport);
rtsp_send_cmd(s, cmd, reply, NULL);
if (reply->status_code != RTSP_STATUS_OK ||
reply->nb_transports != 1) {
err = AVERROR_INVALIDDATA;
goto fail;
}
/* XXX: same protocol for all streams is required */
if (i > 0) {
if (reply->transports[0].protocol != rt->protocol) {
err = AVERROR_INVALIDDATA;
goto fail;
}
} else {
rt->protocol = reply->transports[0].protocol;
}
/* close RTP connection if not choosen */
if (reply->transports[0].protocol != RTSP_PROTOCOL_RTP_UDP &&
(protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP))) {
url_close(rtsp_st->rtp_handle);
rtsp_st->rtp_handle = NULL;
}
switch(reply->transports[0].protocol) {
case RTSP_PROTOCOL_RTP_TCP:
rtsp_st->interleaved_min = reply->transports[0].interleaved_min;
rtsp_st->interleaved_max = reply->transports[0].interleaved_max;
break;
case RTSP_PROTOCOL_RTP_UDP:
{
char url[1024];
/* 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) {
err = AVERROR_INVALIDDATA;
goto fail;
}
}
break;
case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
{
char url[1024];
struct in_addr in;
in.s_addr = htonl(reply->transports[0].destination);
snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d",
inet_ntoa(in),
reply->transports[0].port_min,
reply->transports[0].ttl);
if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) {
err = AVERROR_INVALIDDATA;
goto fail;
}
}
break;
}
/* open the RTP context */
st = NULL;
if (rtsp_st->stream_index >= 0)
st = s->streams[rtsp_st->stream_index];
if (!st)
s->ctx_flags |= AVFMTCTX_NOHEADER;
rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->rtp_handle, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data);
if (!rtsp_st->rtp_ctx) {
err = AVERROR(ENOMEM);
goto fail;
} else {
if(rtsp_st->dynamic_handler) {
rtsp_st->rtp_ctx->dynamic_protocol_context= rtsp_st->dynamic_protocol_context;
rtsp_st->rtp_ctx->parse_packet= rtsp_st->dynamic_handler->parse_packet;
}
}
}
rt->state = RTSP_STATE_IDLE;
rt->seek_timestamp = 0; /* default is to start stream at position
zero */
if (ap->initial_pause) {
/* do not start immediately */
} else {
if (rtsp_read_play(s) < 0) {
err = AVERROR_INVALIDDATA;
goto fail;
}
}
return 0;
fail:
rtsp_close_streams(rt);
av_freep(&content);
url_close(rt->rtsp_hd);
return err;
}
static int tcp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
uint8_t *buf, int buf_size)
{
RTSPState *rt = s->priv_data;
int id, len, i, ret;
RTSPStream *rtsp_st;
#ifdef DEBUG_RTP_TCP
printf("tcp_read_packet:\n");
#endif
redo:
for(;;) {
ret = url_readbuf(rt->rtsp_hd, buf, 1);
#ifdef DEBUG_RTP_TCP
printf("ret=%d c=%02x [%c]\n", ret, buf[0], buf[0]);
#endif
if (ret != 1)
return -1;
if (buf[0] == '$')
break;
}
ret = url_readbuf(rt->rtsp_hd, buf, 3);
if (ret != 3)
return -1;
id = buf[0];
len = AV_RB16(buf + 1);
#ifdef DEBUG_RTP_TCP
printf("id=%d len=%d\n", id, len);
#endif
if (len > buf_size || len < 12)
goto redo;
/* get the data */
ret = url_readbuf(rt->rtsp_hd, buf, len);
if (ret != len)
return -1;
/* find the matching stream */
for(i = 0; i < rt->nb_rtsp_streams; i++) {
rtsp_st = rt->rtsp_streams[i];
if (id >= rtsp_st->interleaved_min &&
id <= rtsp_st->interleaved_max)
goto found;
}
goto redo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -