📄 rtsp.c
字号:
if (av_open_input_file(&rtsp_st->ic, url, fmt, 0, NULL) < 0) { err = AVERROR_INVALIDDATA; goto fail; } } break; } } /* use callback if available to extend setup */ if (ff_rtsp_callback) { if (ff_rtsp_callback(RTSP_ACTION_CLIENT_SETUP, rt->session_id, NULL, 0, rt->last_reply) < 0) { err = AVERROR_INVALIDDATA; goto fail; } } /* start playing */ snprintf(cmd, sizeof(cmd), "PLAY %s RTSP/1.0\n", s->filename); rtsp_send_cmd(s, cmd, reply, NULL); if (reply->status_code != RTSP_STATUS_OK) { err = AVERROR_INVALIDDATA; goto fail; } /* open TCP with bufferized input */ if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) { if (url_fdopen(&rt->rtsp_gb, rt->rtsp_hd) < 0) { err = AVERROR_NOMEM; goto fail; } } return 0; fail: for(i=0;i<s->nb_streams;i++) { st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st) { if (rtsp_st->ic) av_close_input_file(rtsp_st->ic); } av_free(rtsp_st); } av_freep(&content); url_close(rt->rtsp_hd); return err;}static int tcp_read_packet(AVFormatContext *s, AVPacket *pkt){ RTSPState *rt = s->priv_data; ByteIOContext *rtsp_gb = &rt->rtsp_gb; int c, id, len, i, ret; AVStream *st; RTSPStream *rtsp_st; char buf[RTP_MAX_PACKET_LENGTH]; redo: for(;;) { c = url_fgetc(rtsp_gb); if (c == URL_EOF) return AVERROR_IO; if (c == '$') break; } id = get_byte(rtsp_gb); len = get_be16(rtsp_gb); if (len > RTP_MAX_PACKET_LENGTH || len < 12) goto redo; /* get the data */ get_buffer(rtsp_gb, buf, len); /* find the matching stream */ for(i = 0; i < s->nb_streams; i++) { st = s->streams[i]; rtsp_st = st->priv_data; if (i >= rtsp_st->interleaved_min && i <= rtsp_st->interleaved_max) goto found; } goto redo; found: ret = rtp_parse_packet(rtsp_st->ic, pkt, buf, len); if (ret < 0) goto redo; pkt->stream_index = i; return ret;}/* NOTE: output one packet at a time. May need to add a small fifo */static int udp_read_packet(AVFormatContext *s, AVPacket *pkt){ AVFormatContext *ic; AVStream *st; RTSPStream *rtsp_st; fd_set rfds; int fd1, fd2, fd_max, n, i, ret; char buf[RTP_MAX_PACKET_LENGTH]; struct timeval tv; for(;;) { if (rtsp_abort_req) return -EIO; FD_ZERO(&rfds); fd_max = -1; for(i = 0; i < s->nb_streams; i++) { st = s->streams[i]; rtsp_st = st->priv_data; ic = rtsp_st->ic; /* currently, we cannot probe RTCP handle because of blocking restrictions */ rtp_get_file_handles(url_fileno(&ic->pb), &fd1, &fd2); if (fd1 > fd_max) fd_max = fd1; FD_SET(fd1, &rfds); } /* XXX: also add proper API to abort */ tv.tv_sec = 0; tv.tv_usec = 500000; n = select(fd_max + 1, &rfds, NULL, NULL, &tv); if (n > 0) { for(i = 0; i < s->nb_streams; i++) { st = s->streams[i]; rtsp_st = st->priv_data; ic = rtsp_st->ic; rtp_get_file_handles(url_fileno(&ic->pb), &fd1, &fd2); if (FD_ISSET(fd1, &rfds)) { ret = url_read(url_fileno(&ic->pb), buf, sizeof(buf)); if (ret >= 0 && rtp_parse_packet(ic, pkt, buf, ret) == 0) { pkt->stream_index = i; return ret; } } } } }}static int rtsp_read_packet(AVFormatContext *s, AVPacket *pkt){ RTSPState *rt = s->priv_data; int ret; switch(rt->protocol) { default: case RTSP_PROTOCOL_RTP_TCP: ret = tcp_read_packet(s, pkt); break; case RTSP_PROTOCOL_RTP_UDP: ret = udp_read_packet(s, pkt); break; } return ret;}static int rtsp_read_close(AVFormatContext *s){ RTSPState *rt = s->priv_data; AVStream *st; RTSPStream *rtsp_st; RTSPHeader reply1, *reply = &reply1; int i; char cmd[1024]; /* NOTE: it is valid to flush the buffer here */ if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) { url_fclose(&rt->rtsp_gb); } snprintf(cmd, sizeof(cmd), "TEARDOWN %s RTSP/1.0\n", s->filename); rtsp_send_cmd(s, cmd, reply, NULL); if (ff_rtsp_callback) { ff_rtsp_callback(RTSP_ACTION_CLIENT_TEARDOWN, rt->session_id, NULL, 0, NULL); } for(i=0;i<s->nb_streams;i++) { st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st) { if (rtsp_st->ic) av_close_input_file(rtsp_st->ic); } av_free(rtsp_st); } url_close(rt->rtsp_hd); return 0;}static AVInputFormat rtsp_demux = { "rtsp", "RTSP input format", sizeof(RTSPState), rtsp_probe, rtsp_read_header, rtsp_read_packet, rtsp_read_close, .flags = AVFMT_NOFILE,};static int sdp_probe(AVProbeData *p1){ const char *p; /* we look for a line beginning "c=IN IP4" */ p = p1->buf; while (*p != '\0') { if (strstart(p, "c=IN IP4", NULL)) return AVPROBE_SCORE_MAX / 2; p = strchr(p, '\n'); if (!p) break; p++; if (*p == '\r') p++; } return 0;}#define SDP_MAX_SIZE 8192static int sdp_read_header(AVFormatContext *s, AVFormatParameters *ap){ AVStream *st; RTSPStream *rtsp_st; int size, i, err; char *content; char url[1024]; /* read the whole sdp file */ /* XXX: better loading */ content = av_malloc(SDP_MAX_SIZE); size = get_buffer(&s->pb, content, SDP_MAX_SIZE - 1); if (size <= 0) { av_free(content); return AVERROR_INVALIDDATA; } content[size] ='\0'; sdp_parse(s, content); av_free(content); /* open each RTP stream */ for(i=0;i<s->nb_streams;i++) { st = s->streams[i]; rtsp_st = st->priv_data; snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d", inet_ntoa(rtsp_st->sdp_ip), rtsp_st->sdp_port, rtsp_st->sdp_ttl); if (av_open_input_file(&rtsp_st->ic, url, &rtp_demux, 0, NULL) < 0) { err = AVERROR_INVALIDDATA; goto fail; } } return 0; fail: for(i=0;i<s->nb_streams;i++) { st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st) { if (rtsp_st->ic) av_close_input_file(rtsp_st->ic); } av_free(rtsp_st); } return err;}static int sdp_read_packet(AVFormatContext *s, AVPacket *pkt){ return udp_read_packet(s, pkt);}static int sdp_read_close(AVFormatContext *s){ AVStream *st; RTSPStream *rtsp_st; int i; for(i=0;i<s->nb_streams;i++) { st = s->streams[i]; rtsp_st = st->priv_data; if (rtsp_st) { if (rtsp_st->ic) av_close_input_file(rtsp_st->ic); } av_free(rtsp_st); } return 0;}static AVInputFormat sdp_demux = { "sdp", "SDP", sizeof(RTSPState), sdp_probe, sdp_read_header, sdp_read_packet, sdp_read_close,};/* dummy redirector format (used directly in av_open_input_file now) */static int redir_probe(AVProbeData *pd){ const char *p; p = pd->buf; while (redir_isspace(*p)) p++; if (strstart(p, "http://", NULL) || strstart(p, "rtsp://", NULL)) return AVPROBE_SCORE_MAX; return 0;}/* called from utils.c */int redir_open(AVFormatContext **ic_ptr, ByteIOContext *f){ char buf[4096], *q; int c; AVFormatContext *ic = NULL; /* parse each URL and try to open it */ c = url_fgetc(f); while (c != URL_EOF) { /* skip spaces */ for(;;) { if (!redir_isspace(c)) break; c = url_fgetc(f); } if (c == URL_EOF) break; /* record url */ q = buf; for(;;) { if (c == URL_EOF || redir_isspace(c)) break; if ((q - buf) < sizeof(buf) - 1) *q++ = c; c = url_fgetc(f); } *q = '\0'; //printf("URL='%s'\n", buf); /* try to open the media file */ if (av_open_input_file(&ic, buf, NULL, 0, NULL) == 0) break; } *ic_ptr = ic; if (!ic) return AVERROR_IO; else return 0;}AVInputFormat redir_demux = { "redir", "Redirector format", 0, redir_probe, NULL, NULL, NULL,};int rtsp_init(void){ av_register_input_format(&rtsp_demux); av_register_input_format(&redir_demux); av_register_input_format(&sdp_demux); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -