📄 rtsp.c
字号:
do { /* get rtsp reply */ rtsp_hdr->buffer_len += BUFSIZE_1K; rtsp_hdr->buffer = (char *)xrealloc(rtsp_hdr->buffer, rtsp_hdr->buffer_len + 1); i = recv_data(stream,rtsp_hdr->buffer + total,BUFSIZE_1K); if(i <= 0) { display(MSDL_ERR,"rtsp_recv_header error: recv_data() returned %d\n",i); goto failed; } total += i; rtsp_hdr->buffer[total] = '\0'; /* for rtsp_is_entire_header */ } while(!rtsp_is_entire_header(rtsp_hdr)); /* rtsp_hdr->buffer_size is length in buffer, not the malloc()ed size. */ rtsp_hdr->buffer_len = total; rtsp_hdr->buffer[total] = '\0'; ret = rtsp_response_parse(rtsp_hdr); if(ret < 0) { display(MSDL_ERR,"response RTSP header parse failed\n"); goto failed; } /* push body back !!! */ if(rtsp_hdr->body_len) { stream_data_push_back(stream,rtsp_hdr->body,rtsp_hdr->body_len); } /* rtsp_hdr->buffer *ONLY* contains header, no body follows */ memset(rtsp_hdr->body,0,rtsp_hdr->body_len); /* dbg */ display(MSDL_DBG,"rtsp header===========\n" "%s\n" "==(%d bytes)====================\n", rtsp_hdr->buffer,strlen(rtsp_hdr->buffer)); /* success */ return rtsp_hdr->status_code; failed: if(rtsp_hdr->buffer) free(rtsp_hdr->buffer); rtsp_hdr->buffer = NULL; return -1;}/* * set fields which are common in all rtsp packet. * CSeq and Session field should be present in * every rtsp packet. */int rtsp_set_standard_fields(struct rtsp_ctrl_t *rtsp_ctrl, struct rtsp_header_t *rtsp_hdr){ char buf[20]; snprintf(buf,20,"Cseq: %u",rtsp_ctrl->cseq); rtsp_set_field(rtsp_hdr,buf); if(rtsp_ctrl->session) { char *buf2; buf2 = (char *)xmalloc(strlen(rtsp_ctrl->session) + 15); sprintf(buf2,"Session: %s",rtsp_ctrl->session); rtsp_set_field(rtsp_hdr,buf2); free(buf2); } return 0;}/* * send rtsp header (rtsp_hdr->buffer) */int rtsp_send_request(struct stream_t *stream, struct rtsp_header_t *rtsp_hdr){ int ret; /* dbg */ display(MSDL_DBG,"SEND rtsp header ------------>\n" "%s\n--(%d bytes)---------------<\n", rtsp_hdr->buffer,(int)rtsp_hdr->buffer_len); ret = xsend(stream->netsock->sock,rtsp_hdr->buffer,rtsp_hdr->buffer_len); /* OK change stream->stream_ctrl->rtsp_ctrl->cseq!! */ stream->stream_ctrl->rtsp_ctrl->cseq++; return ret;}/* * set basic stuff and send OPTIONS request. * this can be used to determine which protocol to use, * depending on its server. * return value sock : success * -1 : failure */int rtsp_connect(struct stream_t *stream){ int sock; struct stream_ctrl_t *stream_ctrl = stream->stream_ctrl; struct rtsp_ctrl_t *rtsp_ctrl = stream_ctrl->rtsp_ctrl; struct url_t *url = stream->url; set_serverinfo(stream->serverinfo,url->hostname,url->port,NULL,0,RTSP_PORT); rtsp_ctrl->server = NULL; rtsp_ctrl->cseq = 1; rtsp_ctrl->server_state = 0; rtsp_ctrl->server_caps = 0; rtsp_ctrl->session = NULL; rtsp_ctrl->get_media_packet = NULL; /* make mrl */ rtsp_make_mrl(rtsp_ctrl,stream->serverinfo->host,stream->serverinfo->port,url->filepath); sock = server_connect(stream->serverinfo->connect_host,stream->serverinfo->connect_port); if(sock < 0) { /* couldn't connect for some reason. (port closed maybe) */ goto failed; } stream->netsock->sock = sock; /* save socket id */ return sock; failed: return -1;}/* * make mrl from url and set to rtsp_ctrl->mrl * mrl is "rtsp://server.com:port/path/to/file.foo" * --IMPORTANT-- * request URI must be complete according to RFC */int rtsp_make_mrl(struct rtsp_ctrl_t *rtsp_ctrl,char *host,int port,char *filepath){ int len = 0; len = strlen(host) + strlen(filepath) + 32; /* 32 is enough */ rtsp_ctrl->mrl = (char *)xmalloc(len); snprintf(rtsp_ctrl->mrl,len,"rtsp://%s:%i%s", host,port,filepath); return 1;}/* * parse rtsp response * return value: 1 ... success * -1 ... parse error */int rtsp_parse_response(struct rtsp_ctrl_t *rtsp_ctrl, struct rtsp_header_t *rtsp_hdr){ char *field; int answer_cseq; if((field = rtsp_get_field(rtsp_hdr,"Alert")) != NULL) { display(MSDL_ERR,"*** Alert ***\n%s\n",field); } if((field = rtsp_get_field(rtsp_hdr,"Cseq")) != NULL) { sscanf(field,"%d",&answer_cseq); if(answer_cseq != rtsp_ctrl->cseq - 1) { /* -1 because cseq is incremented in build_request */ display(MSDL_DBG,"warning: Cseq mismatch, got %u, expected %u\n", answer_cseq,rtsp_ctrl->cseq - 1); } } if((field = rtsp_get_field(rtsp_hdr,"Server")) != NULL) { while(*field == ' ') field++; if(rtsp_ctrl->server) { /* already has it */ if(strcmp(rtsp_ctrl->server,field)) { /* different server */ display(MSDL_DBG,"warning: got different server\n" " old: %s\n" " new: %s\n",rtsp_ctrl->server,field); free(rtsp_ctrl->server); rtsp_ctrl->server = strdup(field); } } else { /* not set yet */ rtsp_ctrl->server = strdup(field); } } if((field = rtsp_get_field(rtsp_hdr,"Session")) != NULL) { while(*field == ' ') field++; if(rtsp_ctrl->session) { if(strcmp(rtsp_ctrl->session,field)) { /* different session */ display(MSDL_DBG,"warning: got different session\n" " old: [%s]\n" " new: [%s]\n",rtsp_ctrl->session,field); free(rtsp_ctrl->session); rtsp_ctrl->session = strdup(field); } } else { rtsp_ctrl->session = strdup(field); } } /* real only, ignore in other protocol... */ if((field = rtsp_get_field(rtsp_hdr,"RealChallenge1")) != NULL) { while(*field == ' ') field++; if(rtsp_ctrl->challenge) { if(strcmp(rtsp_ctrl->challenge,field)) { /* different server */ display(MSDL_DBG,"warning: got different client challenge\n" " old: %s\n" " new: %s\n",rtsp_ctrl->challenge,field); free(rtsp_ctrl->challenge); rtsp_ctrl->challenge = strdup(field); } } else { rtsp_ctrl->challenge = strdup(field); } } return 1;}/* * rtsp_response_parse : parse rtsp response header * make rtsp_hdr from raw data in rtsp_hdr->buffer * * return value : -1 ... ERROR * 0 ... already parsed. * 1 ... success. */int rtsp_response_parse(struct rtsp_header_t *rtsp_hdr){ char *hdr_ptr, *ptr; char *field = NULL; int pos_hdr_sep, hdr_sep_len; size_t len; if(rtsp_hdr == NULL) return -1; if(rtsp_hdr->is_parsed) return 0; /* already parsed. */ /* get first word */ hdr_ptr = strstr(rtsp_hdr->buffer, " "); if(hdr_ptr == NULL) { display(MSDL_ERR,"Malformed answer : No %20 separator\n"); return -1; } len = hdr_ptr - rtsp_hdr->buffer; rtsp_hdr->protocol = xmalloc(len + 1); strncpy(rtsp_hdr->protocol,rtsp_hdr->buffer,len); rtsp_hdr->protocol[len] = '\0'; /* 1. set method */ rtsp_hdr->method = strdup(rtsp_hdr->protocol); if(!strncasecmp(rtsp_hdr->protocol,"RTSP",4)) { /* RTSP message*/ /* 2. get RTSP status code */ if(sscanf(++hdr_ptr,"%d",&(rtsp_hdr->status_code)) != 1) { display(MSDL_ERR,"Malformed answer : No rtsp status code!!\n"); return -1; } hdr_ptr += 4; /* "[0-9][0-9][0-9] " */ /* 3. get reason phrase */ ptr = strstr(hdr_ptr,"\n"); if(ptr == NULL) { display(MSDL_ERR,"Malformed answer : unable to get reason_phrase\n"); return -1; } len = ptr - hdr_ptr; // len of reason phrase. rtsp_hdr->reason_phrase = xmalloc(len + 1); strncpy(rtsp_hdr->reason_phrase,hdr_ptr,len); if(rtsp_hdr->reason_phrase[len - 1] == '\r') { // M$ style newline! len --; // we don't need \r. } rtsp_hdr->reason_phrase[len] = '\0'; // terminate string } else if(!strncasecmp(rtsp_hdr->protocol,"SET_PARAMETER",strlen("SET_PARAMETER"))) { rtsp_hdr->status_code = RTSP_STATUS_SET_PARAMETER; } else if(!strncasecmp(rtsp_hdr->protocol,"OPTIONS",strlen("OPTIONS"))) { rtsp_hdr->status_code = RTSP_STATUS_OPTIONS; } else if(!strncasecmp(rtsp_hdr->protocol,"ANNOUNCE",strlen("ANNOUNCE"))) { rtsp_hdr->status_code = RTSP_STATUS_ANNOUNCE; } else { /* NOT RTSP ---> abort */ display(MSDL_ERR,"Protocol not RTSP, server says '%s'",rtsp_hdr->protocol); return -1; } hdr_sep_len = 4; /* header separator length */ ptr = strstr(rtsp_hdr->buffer,"\r\n\r\n"); if(!ptr) { ptr = strstr(rtsp_hdr->buffer,"\n\n"); if(!ptr) { display(MSDL_ERR,"Header may be incomplete!\n"); return -1; } hdr_sep_len = 2; } pos_hdr_sep = ptr - rtsp_hdr->buffer; /* points to first line after method line. */ hdr_ptr = strstr(rtsp_hdr->buffer,"\n") + 1; /* parse of first line [DONE] */ /* get all fields. they are separated by '\n' */ do { ptr = hdr_ptr; while(*ptr != '\r' && *ptr != '\n') ptr++; len = ptr - hdr_ptr; if(len == 0) break; /* met \n\n --> end of header! */ field = (char *)xrealloc(field,len + 1); // +1 for '\0' strncpy(field,hdr_ptr,len); field[len] = '\0'; rtsp_set_field(rtsp_hdr,field); hdr_ptr = ptr + ((*ptr == '\r') ? 2 : 1); /* points to next line */ } while(hdr_ptr < (rtsp_hdr->buffer + pos_hdr_sep)); if(field) { free(field); } /* rtsp_hdr->buffer_len is length of header total data received */ if(pos_hdr_sep + hdr_sep_len < rtsp_hdr->buffer_len) { rtsp_hdr->body = rtsp_hdr->buffer + (pos_hdr_sep + hdr_sep_len); rtsp_hdr->body_len = rtsp_hdr->buffer_len - (pos_hdr_sep + hdr_sep_len); } /* mark parsed */ rtsp_hdr->is_parsed = 1; return 1;}/* * start rtsp streaming. * * return value : negative or 0 ... error * 1 ... success */int rtsp_streaming_start(struct stream_t *stream){ struct rtsp_header_t *rtsp_answer = NULL; int header_size; char *answer = NULL; /* temporary pointer */ char *server = NULL; char *redirected = NULL; stream->stream_ctrl->status = STREAMING_HANDSHAKING; if(stream->dlopts->dl_protocol == RTSP_WMS) { server = strdup("WMServer"); } else { /* still don't know which rtsp protocol, or REAL specified (need challenge) */ stream->netsock->sock = rtsp_connect(stream); if(stream->netsock->sock < 0) { display(MSDL_ERR,"cannot establish rtsp connection\n"); goto failed; } real_rtsp_options(stream,&rtsp_answer); if(rtsp_answer == NULL) { display(MSDL_ERR,"rtsp connection failed\n"); goto failed; } /* get server name */ if((answer = rtsp_get_field(rtsp_answer,"Server")) != NULL) { while(*answer == ' ') answer++; /* skip space */ server = strdup(answer); } else { if((rtsp_get_field(rtsp_answer,"RealChallenge1")) != NULL) { server = strdup("Real"); } else { server = strdup("Unknown Server"); } } } /* real or helix server (supported) */ if(strstr(server,"Real") || strstr(server,"Helix")) { /* real-rtsp */ struct rmff_header_t *rmff_header = NULL; int ret = 0; /* connection is already setup, by real_rtsp_options called above */ /* this is the function to do almost all setup process */ ret = real_setup_and_get_header(stream,&rmff_header); if((!rmff_header) || (ret <= 0)) { /* NOT OK */ if((answer = rtsp_get_field(rtsp_answer,"Location")) != NULL) { /* redirected */ while(*answer == ' ') answer++; redirected = strdup(answer); display(MSDL_NOR,"redirected to %s\n",redirected); /* TODO redirection support and I have never seen example... */ goto failed; } else { display(MSDL_ERR,"real/helix connection not established\n"); goto failed; } } /* OK, connection established */ header_size = rmff_dump_header(rmff_header, stream->stream_ctrl->write_buffer); stream->stream_ctrl->write_data_len = header_size; display(MSDL_VER,"rmff_header_size = %d\n",header_size); /* All Green */ stream->stream_ctrl->rtsp_ctrl->rmff_header = rmff_header; stream->stream_ctrl->file_size = rmff_header->data->size; stream->stream_ctrl->total_packets = rmff_header->data->num_packets; stream->stream_ctrl->rtsp_ctrl->get_media_packet = real_rdt_get_media_packet; /* to distinguish which rtsp */ stream->stream_ctrl->rtsp_ctrl->rtsp_protocol = RTSP_REAL_PROTOCOL; /* for msdl function to know protocol */ stream->stream_ctrl->protocol = RTSP_REAL; } else if(strstr(server,"WMServer")) { /* try rtsp-wms */ struct asf_headerinfo_t *asf_headerinfo = NULL; int ret = 0; /* * Clean up first. */ if(stream->netsock->sock) { close(stream->netsock->sock); } /* free rtsp_ctrl_t */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -