📄 rtsp.c
字号:
ttl = 16; if (*p == '/') { p++; get_word_sep(buf1, sizeof(buf1), "/", &p); ttl = atoi(buf1); } if (s->nb_streams == 0) { s1->default_ip = sdp_ip; s1->default_ttl = ttl; } else { st = s->streams[s->nb_streams - 1]; rtsp_st = st->priv_data; rtsp_st->sdp_ip = sdp_ip; rtsp_st->sdp_ttl = ttl; } break; case 's': av_strlcpy(s->title, p, sizeof(s->title)); break; case 'i': if (s->nb_streams == 0) { av_strlcpy(s->comment, p, sizeof(s->comment)); break; } break; case 'm': /* new stream */ get_word(st_type, sizeof(st_type), &p); if (!strcmp(st_type, "audio")) { codec_type = CODEC_TYPE_AUDIO; } else if (!strcmp(st_type, "video")) { codec_type = CODEC_TYPE_VIDEO; } else { return; } rtsp_st = av_mallocz(sizeof(RTSPStream)); if (!rtsp_st) return; rtsp_st->stream_index = -1; dynarray_add(&rt->rtsp_streams, &rt->nb_rtsp_streams, rtsp_st); rtsp_st->sdp_ip = s1->default_ip; rtsp_st->sdp_ttl = s1->default_ttl; get_word(buf1, sizeof(buf1), &p); /* port */ rtsp_st->sdp_port = atoi(buf1); get_word(buf1, sizeof(buf1), &p); /* protocol (ignored) */ /* XXX: handle list of formats */ get_word(buf1, sizeof(buf1), &p); /* format list */ rtsp_st->sdp_payload_type = atoi(buf1); if (!strcmp(ff_rtp_enc_name(rtsp_st->sdp_payload_type), "MP2T")) { /* no corresponding stream */ } else { st = av_new_stream(s, 0); if (!st) return; st->priv_data = rtsp_st; rtsp_st->stream_index = st->index; 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); } } /* put a default control url */ av_strlcpy(rtsp_st->control_url, s->filename, sizeof(rtsp_st->control_url)); break; case 'a': if (av_strstart(p, "control:", &p) && s->nb_streams > 0) { char proto[32]; /* get the control url */ st = s->streams[s->nb_streams - 1]; rtsp_st = st->priv_data; /* XXX: may need to add full url resolution */ url_split(proto, sizeof(proto), NULL, 0, NULL, 0, NULL, NULL, 0, p); if (proto[0] == '\0') { /* relative control URL */ av_strlcat(rtsp_st->control_url, "/", sizeof(rtsp_st->control_url)); av_strlcat(rtsp_st->control_url, p, sizeof(rtsp_st->control_url)); } else { av_strlcpy(rtsp_st->control_url, p, sizeof(rtsp_st->control_url)); } } else if (av_strstart(p, "rtpmap:", &p)) { /* NOTE: rtpmap is only supported AFTER the 'm=' tag */ get_word(buf1, sizeof(buf1), &p); payload_type = atoi(buf1); for(i = 0; i < s->nb_streams;i++) { st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st->sdp_payload_type == payload_type) { sdp_parse_rtpmap(st->codec, rtsp_st, payload_type, p); } } } else if (av_strstart(p, "fmtp:", &p)) { /* NOTE: fmtp is only supported AFTER the 'a=rtpmap:xxx' tag */ get_word(buf1, sizeof(buf1), &p); payload_type = atoi(buf1); for(i = 0; i < s->nb_streams;i++) { st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st->sdp_payload_type == payload_type) { if(rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->parse_sdp_a_line) { if(!rtsp_st->dynamic_handler->parse_sdp_a_line(st, rtsp_st->dynamic_protocol_context, buf)) { sdp_parse_fmtp(st, p); } } else { sdp_parse_fmtp(st, p); } } } } else if(av_strstart(p, "framesize:", &p)) { // let dynamic protocol handlers have a stab at the line. get_word(buf1, sizeof(buf1), &p); payload_type = atoi(buf1); for(i = 0; i < s->nb_streams;i++) { st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st->sdp_payload_type == payload_type) { if(rtsp_st->dynamic_handler && rtsp_st->dynamic_handler->parse_sdp_a_line) { rtsp_st->dynamic_handler->parse_sdp_a_line(st, rtsp_st->dynamic_protocol_context, buf); } } } } else if(av_strstart(p, "range:", &p)) { int64_t start, end; // this is so that seeking on a streamed file can work. rtsp_parse_range_npt(p, &start, &end); s->start_time= start; s->duration= (end==AV_NOPTS_VALUE)?AV_NOPTS_VALUE:end-start; // AV_NOPTS_VALUE means live broadcast (and can't seek) } break; }}static int sdp_parse(AVFormatContext *s, const char *content){ const char *p; int letter; char buf[1024], *q; SDPParseState sdp_parse_state, *s1 = &sdp_parse_state; memset(s1, 0, sizeof(SDPParseState)); p = content; for(;;) { skip_spaces(&p); letter = *p; if (letter == '\0') break; p++; if (*p != '=') goto next_line; p++; /* get the content */ q = buf; while (*p != '\n' && *p != '\r' && *p != '\0') { if ((q - buf) < sizeof(buf) - 1) *q++ = *p; p++; } *q = '\0'; sdp_parse_line(s, s1, letter, buf); next_line: while (*p != '\n' && *p != '\0') p++; if (*p == '\n') p++; } return 0;}static void rtsp_parse_range(int *min_ptr, int *max_ptr, const char **pp){ const char *p; int v; p = *pp; skip_spaces(&p); v = strtol(p, (char **)&p, 10); if (*p == '-') { p++; *min_ptr = v; v = strtol(p, (char **)&p, 10); *max_ptr = v; } else { *min_ptr = v; *max_ptr = v; } *pp = p;}/* XXX: only one transport specification is parsed */static void rtsp_parse_transport(RTSPHeader *reply, const char *p){ char transport_protocol[16]; char profile[16]; char lower_transport[16]; char parameter[16]; RTSPTransportField *th; char buf[256]; reply->nb_transports = 0; for(;;) { skip_spaces(&p); if (*p == '\0') break; th = &reply->transports[reply->nb_transports]; get_word_sep(transport_protocol, sizeof(transport_protocol), "/", &p); if (*p == '/') p++; if (!strcasecmp (transport_protocol, "rtp")) { get_word_sep(profile, sizeof(profile), "/;,", &p); lower_transport[0] = '\0'; /* rtp/avp/<protocol> */ if (*p == '/') { p++; get_word_sep(lower_transport, sizeof(lower_transport), ";,", &p); } } else if (!strcasecmp (transport_protocol, "x-pn-tng")) { /* x-pn-tng/<protocol> */ get_word_sep(lower_transport, sizeof(lower_transport), "/;,", &p); profile[0] = '\0'; } if (!strcasecmp(lower_transport, "TCP")) th->protocol = RTSP_PROTOCOL_RTP_TCP; else th->protocol = RTSP_PROTOCOL_RTP_UDP; if (*p == ';') p++; /* get each parameter */ while (*p != '\0' && *p != ',') { get_word_sep(parameter, sizeof(parameter), "=;,", &p); if (!strcmp(parameter, "port")) { if (*p == '=') { p++; rtsp_parse_range(&th->port_min, &th->port_max, &p); } } else if (!strcmp(parameter, "client_port")) { if (*p == '=') { p++; rtsp_parse_range(&th->client_port_min, &th->client_port_max, &p); } } else if (!strcmp(parameter, "server_port")) { if (*p == '=') { p++; rtsp_parse_range(&th->server_port_min, &th->server_port_max, &p); } } else if (!strcmp(parameter, "interleaved")) { if (*p == '=') { p++; rtsp_parse_range(&th->interleaved_min, &th->interleaved_max, &p); } } else if (!strcmp(parameter, "multicast")) { if (th->protocol == RTSP_PROTOCOL_RTP_UDP) th->protocol = RTSP_PROTOCOL_RTP_UDP_MULTICAST; } else if (!strcmp(parameter, "ttl")) { if (*p == '=') { p++; th->ttl = strtol(p, (char **)&p, 10); } } else if (!strcmp(parameter, "destination")) { struct in_addr ipaddr; if (*p == '=') { p++; get_word_sep(buf, sizeof(buf), ";,", &p); if (inet_aton(buf, &ipaddr)) th->destination = ntohl(ipaddr.s_addr); } } while (*p != ';' && *p != '\0' && *p != ',') p++; if (*p == ';') p++; } if (*p == ',') p++; reply->nb_transports++; }}void rtsp_parse_line(RTSPHeader *reply, const char *buf){ const char *p; /* NOTE: we do case independent match for broken servers */ p = buf; if (av_stristart(p, "Session:", &p)) { get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p); } else if (av_stristart(p, "Content-Length:", &p)) { reply->content_length = strtol(p, NULL, 10); } else if (av_stristart(p, "Transport:", &p)) { rtsp_parse_transport(reply, p); } else if (av_stristart(p, "CSeq:", &p)) { reply->seq = strtol(p, NULL, 10); } else if (av_stristart(p, "Range:", &p)) { rtsp_parse_range_npt(p, &reply->range_start, &reply->range_end); }}static int url_readbuf(URLContext *h, unsigned char *buf, int size){ int ret, len; len = 0; while (len < size) { ret = url_read(h, buf+len, size-len); if (ret < 1) return ret; len += ret; } return len;}/* skip a RTP/TCP interleaved packet */static void rtsp_skip_packet(AVFormatContext *s){ RTSPState *rt = s->priv_data; int ret, len, len1; uint8_t buf[1024]; ret = url_readbuf(rt->rtsp_hd, buf, 3); if (ret != 3) return; len = AV_RB16(buf + 1);#ifdef DEBUG printf("skipping RTP packet len=%d\n", len);#endif /* skip payload */ while (len > 0) { len1 = len; if (len1 > sizeof(buf)) len1 = sizeof(buf); ret = url_readbuf(rt->rtsp_hd, buf, len1); if (ret != len1) return; len -= len1; }}static void rtsp_send_cmd(AVFormatContext *s, const char *cmd, RTSPHeader *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; 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#ifdef __CW32__ url_write(rt->rtsp_hd, (unsigned char*)buf, strlen(buf));#else url_write(rt->rtsp_hd, buf, strlen(buf));#endif /* parse reply (XXX: use buffers) */ line_count = 0; rt->last_reply[0] = '\0'; for(;;) { q = buf; for(;;) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -