?? ffserver.c
字號:
pstrcpy(pathname, sizeof(pathname), my_program_name); slash = strrchr(pathname, '/'); if (!slash) { slash = pathname; } else { slash++; } strcpy(slash, "ffmpeg"); /* This is needed to make relative pathnames work */ chdir(my_program_dir); signal(SIGPIPE, SIG_DFL); execvp(pathname, feed->child_argv); _exit(1); } } }}/* open a listening socket */static int socket_open_listen(struct sockaddr_in *my_addr){ int server_fd, tmp; server_fd = socket(AF_INET,SOCK_STREAM,0); if (server_fd < 0) { perror ("socket"); return -1; } tmp = 1; setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)); if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) { char bindmsg[32]; snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port)); perror (bindmsg); close(server_fd); return -1; } if (listen (server_fd, 5) < 0) { perror ("listen"); close(server_fd); return -1; } fcntl(server_fd, F_SETFL, O_NONBLOCK); return server_fd;}/* start all multicast streams */static void start_multicast(void){ FFStream *stream; char session_id[32]; HTTPContext *rtp_c; struct sockaddr_in dest_addr; int default_port, stream_index; default_port = 6000; for(stream = first_stream; stream != NULL; stream = stream->next) { if (stream->is_multicast) { /* open the RTP connection */ snprintf(session_id, sizeof(session_id), "%08x%08x", (int)random(), (int)random()); /* choose a port if none given */ if (stream->multicast_port == 0) { stream->multicast_port = default_port; default_port += 100; } dest_addr.sin_family = AF_INET; dest_addr.sin_addr = stream->multicast_ip; dest_addr.sin_port = htons(stream->multicast_port); rtp_c = rtp_new_connection(&dest_addr, stream, session_id, RTSP_PROTOCOL_RTP_UDP_MULTICAST); if (!rtp_c) { continue; } if (open_input_stream(rtp_c, "") < 0) { fprintf(stderr, "Could not open input stream for stream '%s'\n", stream->filename); continue; } /* open each RTP stream */ for(stream_index = 0; stream_index < stream->nb_streams; stream_index++) { dest_addr.sin_port = htons(stream->multicast_port + 2 * stream_index); if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) { fprintf(stderr, "Could not open output stream '%s/streamid=%d'\n", stream->filename, stream_index); exit(1); } } /* change state to send data */ rtp_c->state = HTTPSTATE_SEND_DATA; } }}/* main loop of the http server */static int http_server(void){ int server_fd, ret, rtsp_server_fd, delay, delay1; struct pollfd poll_table[HTTP_MAX_CONNECTIONS + 2], *poll_entry; HTTPContext *c, *c_next; server_fd = socket_open_listen(&my_http_addr); if (server_fd < 0) return -1; rtsp_server_fd = socket_open_listen(&my_rtsp_addr); if (rtsp_server_fd < 0) return -1; http_log("ffserver started.\n"); start_children(first_feed); first_http_ctx = NULL; nb_connections = 0; start_multicast(); for(;;) { poll_entry = poll_table; poll_entry->fd = server_fd; poll_entry->events = POLLIN; poll_entry++; poll_entry->fd = rtsp_server_fd; poll_entry->events = POLLIN; poll_entry++; /* wait for events on each HTTP handle */ c = first_http_ctx; delay = 1000; while (c != NULL) { int fd; fd = c->fd; switch(c->state) { case HTTPSTATE_SEND_HEADER: case RTSPSTATE_SEND_REPLY: case RTSPSTATE_SEND_PACKET: c->poll_entry = poll_entry; poll_entry->fd = fd; poll_entry->events = POLLOUT; poll_entry++; break; case HTTPSTATE_SEND_DATA_HEADER: case HTTPSTATE_SEND_DATA: case HTTPSTATE_SEND_DATA_TRAILER: if (!c->is_packetized) { /* for TCP, we output as much as we can (may need to put a limit) */ c->poll_entry = poll_entry; poll_entry->fd = fd; poll_entry->events = POLLOUT; poll_entry++; } else { /* when ffserver is doing the timing, we work by looking at which packet need to be sent every 10 ms */ delay1 = 10; /* one tick wait XXX: 10 ms assumed */ if (delay1 < delay) delay = delay1; } break; case HTTPSTATE_WAIT_REQUEST: case HTTPSTATE_RECEIVE_DATA: case HTTPSTATE_WAIT_FEED: case RTSPSTATE_WAIT_REQUEST: /* need to catch errors */ c->poll_entry = poll_entry; poll_entry->fd = fd; poll_entry->events = POLLIN;/* Maybe this will work */ poll_entry++; break; default: c->poll_entry = NULL; break; } c = c->next; } /* wait for an event on one connection. We poll at least every second to handle timeouts */ do { ret = poll(poll_table, poll_entry - poll_table, delay); if (ret < 0 && errno != EAGAIN && errno != EINTR) return -1; } while (ret <= 0); cur_time = gettime_ms(); if (need_to_start_children) { need_to_start_children = 0; start_children(first_feed); } /* now handle the events */ for(c = first_http_ctx; c != NULL; c = c_next) { c_next = c->next; if (handle_connection(c) < 0) { /* close and free the connection */ log_connection(c); close_connection(c); } } poll_entry = poll_table; /* new HTTP connection request ? */ if (poll_entry->revents & POLLIN) { new_connection(server_fd, 0); } poll_entry++; /* new RTSP connection request ? */ if (poll_entry->revents & POLLIN) { new_connection(rtsp_server_fd, 1); } }}/* start waiting for a new HTTP/RTSP request */static void start_wait_request(HTTPContext *c, int is_rtsp){ c->buffer_ptr = c->buffer; c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */ if (is_rtsp) { c->timeout = cur_time + RTSP_REQUEST_TIMEOUT; c->state = RTSPSTATE_WAIT_REQUEST; } else { c->timeout = cur_time + HTTP_REQUEST_TIMEOUT; c->state = HTTPSTATE_WAIT_REQUEST; }}static void new_connection(int server_fd, int is_rtsp){ struct sockaddr_in from_addr; int fd, len; HTTPContext *c = NULL; len = sizeof(from_addr); fd = accept(server_fd, (struct sockaddr *)&from_addr, &len); if (fd < 0) return; fcntl(fd, F_SETFL, O_NONBLOCK); /* XXX: should output a warning page when coming close to the connection limit */ if (nb_connections >= nb_max_connections) goto fail; /* add a new connection */ c = av_mallocz(sizeof(HTTPContext)); if (!c) goto fail; c->fd = fd; c->poll_entry = NULL; c->from_addr = from_addr; c->buffer_size = IOBUFFER_INIT_SIZE; c->buffer = av_malloc(c->buffer_size); if (!c->buffer) goto fail; c->next = first_http_ctx; first_http_ctx = c; nb_connections++; start_wait_request(c, is_rtsp); return; fail: if (c) { av_free(c->buffer); av_free(c); } close(fd);}static void close_connection(HTTPContext *c){ HTTPContext **cp, *c1; int i, nb_streams; AVFormatContext *ctx; URLContext *h; AVStream *st; /* remove connection from list */ cp = &first_http_ctx; while ((*cp) != NULL) { c1 = *cp; if (c1 == c) { *cp = c->next; } else { cp = &c1->next; } } /* remove references, if any (XXX: do it faster) */ for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) { if (c1->rtsp_c == c) c1->rtsp_c = NULL; } /* remove connection associated resources */ if (c->fd >= 0) close(c->fd); if (c->fmt_in) { /* close each frame parser */ for(i=0;i<c->fmt_in->nb_streams;i++) { st = c->fmt_in->streams[i]; if (st->codec->codec) { avcodec_close(st->codec); } } av_close_input_file(c->fmt_in); } /* free RTP output streams if any */ nb_streams = 0; if (c->stream) nb_streams = c->stream->nb_streams; for(i=0;i<nb_streams;i++) { ctx = c->rtp_ctx[i]; if (ctx) { av_write_trailer(ctx); av_free(ctx); } h = c->rtp_handles[i]; if (h) { url_close(h); } } ctx = &c->fmt_ctx; if (!c->last_packet_sent) { if (ctx->oformat) { /* prepare header */ if (url_open_dyn_buf(&ctx->pb) >= 0) { av_write_trailer(ctx); url_close_dyn_buf(&ctx->pb, &c->pb_buffer); } } } for(i=0; i<ctx->nb_streams; i++) av_free(ctx->streams[i]) ; if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE) current_bandwidth -= c->stream->bandwidth; av_freep(&c->pb_buffer); av_freep(&c->packet_buffer); av_free(c->buffer); av_free(c); nb_connections--;}static int handle_connection(HTTPContext *c){ int len, ret; switch(c->state) { case HTTPSTATE_WAIT_REQUEST: case RTSPSTATE_WAIT_REQUEST: /* timeout ? */ if ((c->timeout - cur_time) < 0) return -1; if (c->poll_entry->revents & (POLLERR | POLLHUP)) return -1; /* no need to read if no events */ if (!(c->poll_entry->revents & POLLIN)) return 0; /* read the data */ read_loop: len = read(c->fd, c->buffer_ptr, 1); if (len < 0) { if (errno != EAGAIN && errno != EINTR) return -1; } else if (len == 0) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -