📄 rtsp.c
字号:
found:
*prtsp_st = rtsp_st;
return len;
}
static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st,
uint8_t *buf, int buf_size)
{
RTSPState *rt = s->priv_data;
RTSPStream *rtsp_st;
fd_set rfds;
int fd1, fd2, fd_max, n, i, ret;
struct timeval tv;
for(;;) {
if (url_interrupt_cb())
return -1;
FD_ZERO(&rfds);
fd_max = -1;
for(i = 0; i < rt->nb_rtsp_streams; i++) {
rtsp_st = rt->rtsp_streams[i];
/* currently, we cannot probe RTCP handle because of blocking restrictions */
rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2);
if (fd1 > fd_max)
fd_max = fd1;
FD_SET(fd1, &rfds);
}
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
n = select(fd_max + 1, &rfds, NULL, NULL, &tv);
if (n > 0) {
for(i = 0; i < rt->nb_rtsp_streams; i++) {
rtsp_st = rt->rtsp_streams[i];
rtp_get_file_handles(rtsp_st->rtp_handle, &fd1, &fd2);
if (FD_ISSET(fd1, &rfds)) {
ret = url_read(rtsp_st->rtp_handle, buf, buf_size);
if (ret > 0) {
*prtsp_st = rtsp_st;
return ret;
}
}
}
}
}
}
static int rtsp_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
RTSPState *rt = s->priv_data;
RTSPStream *rtsp_st;
int ret, len;
uint8_t buf[RTP_MAX_PACKET_LENGTH];
/* get next frames from the same RTP packet */
if (rt->cur_rtp) {
ret = rtp_parse_packet(rt->cur_rtp, pkt, NULL, 0);
if (ret == 0) {
rt->cur_rtp = NULL;
return 0;
} else if (ret == 1) {
return 0;
} else {
rt->cur_rtp = NULL;
}
}
/* read next RTP packet */
redo:
switch(rt->protocol) {
default:
case RTSP_PROTOCOL_RTP_TCP:
len = tcp_read_packet(s, &rtsp_st, buf, sizeof(buf));
break;
case RTSP_PROTOCOL_RTP_UDP:
case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
len = udp_read_packet(s, &rtsp_st, buf, sizeof(buf));
if (len >=0 && rtsp_st->rtp_ctx)
rtp_check_and_send_back_rr(rtsp_st->rtp_ctx, len);
break;
}
if (len < 0)
return AVERROR(EIO);
ret = rtp_parse_packet(rtsp_st->rtp_ctx, pkt, buf, len);
if (ret < 0)
goto redo;
if (ret == 1) {
/* more packets may follow, so we save the RTP context */
rt->cur_rtp = rtsp_st->rtp_ctx;
}
return 0;
}
static int rtsp_read_play(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
RTSPHeader reply1, *reply = &reply1;
char cmd[1024];
av_log(s, AV_LOG_DEBUG, "hello state=%d\n", rt->state);
if (rt->state == RTSP_STATE_PAUSED) {
snprintf(cmd, sizeof(cmd),
"PLAY %s RTSP/1.0\r\n",
s->filename);
} else {
snprintf(cmd, sizeof(cmd),
"PLAY %s RTSP/1.0\r\n"
"Range: npt=%0.3f-\r\n",
s->filename,
(double)rt->seek_timestamp / AV_TIME_BASE);
}
rtsp_send_cmd(s, cmd, reply, NULL);
if (reply->status_code != RTSP_STATUS_OK) {
return -1;
} else {
rt->state = RTSP_STATE_PLAYING;
return 0;
}
}
/* pause the stream */
static int rtsp_read_pause(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
RTSPHeader reply1, *reply = &reply1;
char cmd[1024];
rt = s->priv_data;
if (rt->state != RTSP_STATE_PLAYING)
return 0;
snprintf(cmd, sizeof(cmd),
"PAUSE %s RTSP/1.0\r\n",
s->filename);
rtsp_send_cmd(s, cmd, reply, NULL);
if (reply->status_code != RTSP_STATUS_OK) {
return -1;
} else {
rt->state = RTSP_STATE_PAUSED;
return 0;
}
}
static int rtsp_read_seek(AVFormatContext *s, int stream_index,
int64_t timestamp, int flags)
{
RTSPState *rt = s->priv_data;
rt->seek_timestamp = av_rescale_q(timestamp, s->streams[stream_index]->time_base, AV_TIME_BASE_Q);
switch(rt->state) {
default:
case RTSP_STATE_IDLE:
break;
case RTSP_STATE_PLAYING:
if (rtsp_read_play(s) != 0)
return -1;
break;
case RTSP_STATE_PAUSED:
rt->state = RTSP_STATE_IDLE;
break;
}
return 0;
}
static int rtsp_read_close(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
RTSPHeader reply1, *reply = &reply1;
char cmd[1024];
#if 0
/* NOTE: it is valid to flush the buffer here */
if (rt->protocol == RTSP_PROTOCOL_RTP_TCP) {
url_fclose(&rt->rtsp_gb);
}
#endif
snprintf(cmd, sizeof(cmd),
"TEARDOWN %s RTSP/1.0\r\n",
s->filename);
rtsp_send_cmd(s, cmd, reply, NULL);
rtsp_close_streams(rt);
url_close(rt->rtsp_hd);
return 0;
}
#ifdef CONFIG_RTSP_DEMUXER
AVInputFormat rtsp_demuxer = {
"rtsp",
"RTSP input format",
sizeof(RTSPState),
rtsp_probe,
rtsp_read_header,
rtsp_read_packet,
rtsp_read_close,
rtsp_read_seek,
.flags = AVFMT_NOFILE,
.read_play = rtsp_read_play,
.read_pause = rtsp_read_pause,
};
#endif
static int sdp_probe(AVProbeData *p1)
{
const char *p = p1->buf, *p_end = p1->buf + p1->buf_size;
/* we look for a line beginning "c=IN IP4" */
while (p < p_end && *p != '\0') {
if (p + sizeof("c=IN IP4") - 1 < p_end && av_strstart(p, "c=IN IP4", NULL))
return AVPROBE_SCORE_MAX / 2;
while(p < p_end - 1 && *p != '\n') p++;
if (++p >= p_end)
break;
if (*p == '\r')
p++;
}
return 0;
}
#define SDP_MAX_SIZE 8192
static int sdp_read_header(AVFormatContext *s,
AVFormatParameters *ap)
{
RTSPState *rt = s->priv_data;
RTSPStream *rtsp_st;
int size, i, err;
char *content;
char url[1024];
AVStream *st;
/* 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<rt->nb_rtsp_streams;i++) {
rtsp_st = rt->rtsp_streams[i];
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 (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) {
err = AVERROR_INVALIDDATA;
goto fail;
}
/* 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:
rtsp_close_streams(rt);
return err;
}
static int sdp_read_packet(AVFormatContext *s,
AVPacket *pkt)
{
return rtsp_read_packet(s, pkt);
}
static int sdp_read_close(AVFormatContext *s)
{
RTSPState *rt = s->priv_data;
rtsp_close_streams(rt);
return 0;
}
#ifdef CONFIG_SDP_DEMUXER
AVInputFormat sdp_demuxer = {
"sdp",
"SDP",
sizeof(RTSPState),
sdp_probe,
sdp_read_header,
sdp_read_packet,
sdp_read_close,
};
#endif
#ifdef CONFIG_REDIR_DEMUXER
/* 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 (av_strstart(p, "http://", NULL) ||
av_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(EIO);
else
return 0;
}
AVInputFormat redir_demuxer = {
"redir",
"Redirector format",
0,
redir_probe,
NULL,
NULL,
NULL,
};
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -