📄 rtsp.c
字号:
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(rt->rtsp_streams);}/** * @returns 0 on success, <0 on error, 1 if protocol is unavailable. */static intmake_setup_request (AVFormatContext *s, const char *host, int port, int protocol){ RTSPState *rt = s->priv_data; int j, i, err; RTSPStream *rtsp_st; AVStream *st; RTSPHeader reply1, *reply = &reply1; char cmd[2048]; /* 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 == 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://%s?localport=%d", host, j); j += 2; /* we will use two port by rtp stream (rtp and rtcp) */ if (url_open(&rtsp_st->rtp_handle, buf, URL_RDWR) == 0) { 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 == 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 == 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 == 461 /* Unsupported protocol */ && i == 0) { err = 1; goto fail; } else 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 == 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?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; } } } return 0;fail: for (i=0; i<rt->nb_rtsp_streams; i++) { if (rt->rtsp_streams[i]->rtp_handle) { url_close(rt->rtsp_streams[i]->rtp_handle); rt->rtsp_streams[i]->rtp_handle = NULL; } } return err;}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, ret, err; RTSPHeader reply1, *reply = &reply1; unsigned char *content = NULL; int protocol_mask = 0; /* 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 = (1 << RTSP_PROTOCOL_RTP_LAST) - 1; /* 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; } do { int protocol = ff_log2_tab[protocol_mask & ~(protocol_mask - 1)]; err = make_setup_request(s, host, port, protocol); if (err < 0) goto fail; protocol_mask &= ~(1 << protocol); if (protocol_mask == 0 && err == 1) { err = AVERROR(FF_NETERROR(EPROTONOSUPPORT)); goto fail; } } while (err); 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; found: *prtsp_st = rtsp_st; return len;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -