⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtsp.c

📁 ffmpeg的完整源代码和作者自己写的文档。不但有在Linux的工程哦
💻 C
📖 第 1 页 / 共 4 页
字号:
 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 + -