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

📄 rtsp.c

📁 ffmpeg源码分析
💻 C
📖 第 1 页 / 共 3 页
字号:
        /* 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++;        get_word_sep(profile, sizeof(profile), "/;,", &p);        lower_transport[0] = '\0';        if (*p == '/') {            p++;            get_word_sep(lower_transport, sizeof(lower_transport),                         ";,", &p);        }        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++;    }}static void rtsp_parse_range_npt(RTSPHeader *reply, const char *p){    char buf[256];    skip_spaces(&p);    if (!stristart(p, "npt=", &p))        return;    reply->range_start = AV_NOPTS_VALUE;    reply->range_end = AV_NOPTS_VALUE;    get_word_sep(buf, sizeof(buf), "-", &p);    reply->range_start = parse_date(buf, 1);    if (*p == '-') {        p++;        get_word_sep(buf, sizeof(buf), "-", &p);        reply->range_end = parse_date(buf, 1);    }}void rtsp_parse_line(RTSPHeader *reply, const char *buf){    const char *p;    /* NOTE: we do case independent match for broken servers */    p = buf;    if (stristart(p, "Session:", &p)) {        get_word_sep(reply->session_id, sizeof(reply->session_id), ";", &p);    } else if (stristart(p, "Content-Length:", &p)) {        reply->content_length = strtol(p, NULL, 10);    } else if (stristart(p, "Transport:", &p)) {        rtsp_parse_transport(reply, p);    } else if (stristart(p, "CSeq:", &p)) {        reply->seq = strtol(p, NULL, 10);    } else if (stristart(p, "Range:", &p)) {        rtsp_parse_range_npt(reply, p);    }}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 = (buf[1] << 8) | buf[2];#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++;    pstrcpy(buf, sizeof(buf), cmd);    snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq);    pstrcat(buf, sizeof(buf), buf1);    if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) {        snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id);        pstrcat(buf, sizeof(buf), buf1);    }    pstrcat(buf, sizeof(buf), "\r\n");#ifdef DEBUG    printf("Sending:\n%s--\n", buf);#endif    url_write(rt->rtsp_hd, buf, strlen(buf));    /* parse reply (XXX: use buffers) */    line_count = 0;    rt->last_reply[0] = '\0';    for(;;) {        q = buf;        for(;;) {            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);            pstrcat(rt->last_reply, sizeof(rt->last_reply), p);            pstrcat(rt->last_reply, sizeof(rt->last_reply), "\n");        }        line_count++;    }    if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0')        pstrcpy(rt->session_id, sizeof(rt->session_id), reply->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;}/* useful for modules: set RTSP callback function */void rtsp_set_callback(FFRTSPCallback *rtsp_cb){    ff_rtsp_callback = rtsp_cb;}/* 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);        }        av_free(rtsp_st);    }    av_free(rt->rtsp_streams);}static int rtsp_read_header(AVFormatContext *s,                            AVFormatParameters *ap){    RTSPState *rt = s->priv_data;    char host[1024], path[1024], tcpname[1024], cmd[2048];    URLContext *rtsp_hd;    int port, i, j, ret, err;    RTSPHeader reply1, *reply = &reply1;    unsigned char *content = NULL;    RTSPStream *rtsp_st;    int protocol_mask;    AVStream *st;    /* 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;    /* open the tcp connexion */    snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port);    if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0)        return AVERROR_IO;    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;    }    protocol_mask = rtsp_default_protocols;    /* 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_mask & (1 << 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://?localport=%d", j);                    if (url_open(&rtsp_st->rtp_handle, buf, URL_RDONLY) == 0) {                        j += 2; /* we will use two port by rtp stream (rtp and rtcp) */                        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')                pstrcat(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_mask & (1 << RTSP_PROTOCOL_RTP_TCP)) {            if (transport[0] != '\0')                pstrcat(transport, sizeof(transport), ",");            snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1,                     "RTP/AVP/TCP");        }        else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST)) {            if (transport[0] != '\0')                pstrcat(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 != 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_mask & (1 << 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];                int ttl;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -