2 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * multiple format streaming server based on the FFmpeg libraries
28 #define closesocket close
33 #include "libavformat/avformat.h"
34 // FIXME those are internal headers, ffserver _really_ shouldn't use them
35 #include "libavformat/ffm.h"
36 #include "libavformat/network.h"
37 #include "libavformat/os_support.h"
38 #include "libavformat/rtpdec.h"
39 #include "libavformat/rtpproto.h"
40 #include "libavformat/rtsp.h"
41 #include "libavformat/rtspcodes.h"
42 #include "libavformat/avio_internal.h"
43 #include "libavformat/internal.h"
44 #include "libavformat/url.h"
46 #include "libavutil/avassert.h"
47 #include "libavutil/avstring.h"
48 #include "libavutil/lfg.h"
49 #include "libavutil/dict.h"
50 #include "libavutil/intreadwrite.h"
51 #include "libavutil/mathematics.h"
52 #include "libavutil/random_seed.h"
53 #include "libavutil/parseutils.h"
54 #include "libavutil/opt.h"
55 #include "libavutil/time.h"
62 #include <sys/ioctl.h>
72 #include "ffserver_config.h"
74 const char program_name[] = "ffserver";
75 const int program_birth_year = 2000;
77 static const OptionDef options[];
80 HTTPSTATE_WAIT_REQUEST,
81 HTTPSTATE_SEND_HEADER,
82 HTTPSTATE_SEND_DATA_HEADER,
83 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
84 HTTPSTATE_SEND_DATA_TRAILER,
85 HTTPSTATE_RECEIVE_DATA,
86 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
89 RTSPSTATE_WAIT_REQUEST,
91 RTSPSTATE_SEND_PACKET,
94 static const char * const http_state[] = {
110 #define IOBUFFER_INIT_SIZE 8192
112 /* timeouts are in ms */
113 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
114 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
116 #define SYNC_TIMEOUT (10 * 1000)
118 typedef struct RTSPActionServerSetup {
120 char transport_option[512];
121 } RTSPActionServerSetup;
124 int64_t count1, count2;
125 int64_t time1, time2;
128 /* context associated with one connection */
129 typedef struct HTTPContext {
130 enum HTTPState state;
131 int fd; /* socket file descriptor */
132 struct sockaddr_in from_addr; /* origin */
133 struct pollfd *poll_entry; /* used when polling */
135 uint8_t *buffer_ptr, *buffer_end;
138 int chunked_encoding;
139 int chunk_size; /* 0 if it needs to be read */
140 struct HTTPContext *next;
141 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
145 /* input format handling */
146 AVFormatContext *fmt_in;
147 int64_t start_time; /* In milliseconds - this wraps fairly often */
148 int64_t first_pts; /* initial pts value */
149 int64_t cur_pts; /* current pts value from the stream in us */
150 int64_t cur_frame_duration; /* duration of the current frame in us */
151 int cur_frame_bytes; /* output frame size, needed to compute
152 the time at which we send each
154 int pts_stream_index; /* stream we choose as clock reference */
155 int64_t cur_clock; /* current clock reference value in us */
156 /* output format handling */
157 struct FFServerStream *stream;
158 /* -1 is invalid stream */
159 int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
160 int switch_feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */
162 AVFormatContext fmt_ctx; /* instance of FFServerStream for one user */
163 int last_packet_sent; /* true if last data packet was sent */
165 DataRateData datarate;
172 int is_packetized; /* if true, the stream is packetized */
173 int packet_stream_index; /* current stream for output in state machine */
175 /* RTSP state specific */
176 uint8_t *pb_buffer; /* XXX: use that in all the code */
178 int seq; /* RTSP sequence number */
180 /* RTP state specific */
181 enum RTSPLowerTransport rtp_protocol;
182 char session_id[32]; /* session id */
183 AVFormatContext *rtp_ctx[FFSERVER_MAX_STREAMS];
185 /* RTP/UDP specific */
186 URLContext *rtp_handles[FFSERVER_MAX_STREAMS];
188 /* RTP/TCP specific */
189 struct HTTPContext *rtsp_c;
190 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
193 typedef struct FeedData {
194 long long data_count;
195 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
198 static HTTPContext *first_http_ctx;
200 static FFServerConfig config = {
201 .nb_max_http_connections = 2000,
202 .nb_max_connections = 5,
203 .max_bandwidth = 1000,
207 static void new_connection(int server_fd, int is_rtsp);
208 static void close_connection(HTTPContext *c);
211 static int handle_connection(HTTPContext *c);
212 static int http_parse_request(HTTPContext *c);
213 static int http_send_data(HTTPContext *c);
214 static void compute_status(HTTPContext *c);
215 static int open_input_stream(HTTPContext *c, const char *info);
216 static int http_start_receive_data(HTTPContext *c);
217 static int http_receive_data(HTTPContext *c);
220 static int rtsp_parse_request(HTTPContext *c);
221 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
222 static void rtsp_cmd_options(HTTPContext *c, const char *url);
223 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
224 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
225 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only);
228 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
229 struct in_addr my_ip);
232 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
233 FFServerStream *stream, const char *session_id,
234 enum RTSPLowerTransport rtp_protocol);
235 static int rtp_new_av_stream(HTTPContext *c,
236 int stream_index, struct sockaddr_in *dest_addr,
237 HTTPContext *rtsp_c);
239 static const char *my_program_name;
241 static int no_launch;
242 static int need_to_start_children;
244 /* maximum number of simultaneous HTTP connections */
245 static unsigned int nb_connections;
247 static uint64_t current_bandwidth;
249 static int64_t cur_time; // Making this global saves on passing it around everywhere
251 static AVLFG random_state;
253 static FILE *logfile = NULL;
255 static void htmlstrip(char *s) {
257 s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
263 static int64_t ffm_read_write_index(int fd)
267 if (lseek(fd, 8, SEEK_SET) < 0)
269 if (read(fd, buf, 8) != 8)
274 static int ffm_write_write_index(int fd, int64_t pos)
280 buf[i] = (pos >> (56 - i * 8)) & 0xff;
281 if (lseek(fd, 8, SEEK_SET) < 0)
283 if (write(fd, buf, 8) != 8)
288 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
291 FFMContext *ffm = s->priv_data;
292 ffm->write_index = pos;
293 ffm->file_size = file_size;
296 static char *ctime1(char *buf2, int buf_size)
303 av_strlcpy(buf2, p, buf_size);
304 p = buf2 + strlen(p) - 1;
310 static void http_vlog(const char *fmt, va_list vargs)
312 static int print_prefix = 1;
316 ctime1(buf, sizeof(buf));
317 fprintf(logfile, "%s ", buf);
319 print_prefix = strstr(fmt, "\n") != NULL;
320 vfprintf(logfile, fmt, vargs);
326 __attribute__ ((format (printf, 1, 2)))
328 static void http_log(const char *fmt, ...)
331 va_start(vargs, fmt);
332 http_vlog(fmt, vargs);
336 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
338 static int print_prefix = 1;
339 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
340 if (level > av_log_get_level())
342 if (print_prefix && avc)
343 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
344 print_prefix = strstr(fmt, "\n") != NULL;
345 http_vlog(fmt, vargs);
348 static void log_connection(HTTPContext *c)
353 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
354 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
355 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
358 static void update_datarate(DataRateData *drd, int64_t count)
360 if (!drd->time1 && !drd->count1) {
361 drd->time1 = drd->time2 = cur_time;
362 drd->count1 = drd->count2 = count;
363 } else if (cur_time - drd->time2 > 5000) {
364 drd->time1 = drd->time2;
365 drd->count1 = drd->count2;
366 drd->time2 = cur_time;
371 /* In bytes per second */
372 static int compute_datarate(DataRateData *drd, int64_t count)
374 if (cur_time == drd->time1)
377 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
381 static void start_children(FFServerStream *feed)
386 for (; feed; feed = feed->next) {
387 if (feed->child_argv && !feed->pid) {
388 feed->pid_start = time(0);
393 http_log("Unable to create children\n");
402 /* replace "ffserver" with "ffmpeg" in the path of current
403 * program. Ignore user provided path */
404 av_strlcpy(pathname, my_program_name, sizeof(pathname));
405 slash = strrchr(pathname, '/');
410 strcpy(slash, "ffmpeg");
412 http_log("Launch command line: ");
413 http_log("%s ", pathname);
414 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
415 http_log("%s ", feed->child_argv[i]);
418 for (i = 3; i < 256; i++)
422 if (!freopen("/dev/null", "r", stdin))
423 http_log("failed to redirect STDIN to /dev/null\n;");
424 if (!freopen("/dev/null", "w", stdout))
425 http_log("failed to redirect STDOUT to /dev/null\n;");
426 if (!freopen("/dev/null", "w", stderr))
427 http_log("failed to redirect STDERR to /dev/null\n;");
430 signal(SIGPIPE, SIG_DFL);
432 execvp(pathname, feed->child_argv);
440 /* open a listening socket */
441 static int socket_open_listen(struct sockaddr_in *my_addr)
445 server_fd = socket(AF_INET,SOCK_STREAM,0);
452 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)))
453 av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n");
455 my_addr->sin_family = AF_INET;
456 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
458 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
460 closesocket(server_fd);
464 if (listen (server_fd, 5) < 0) {
466 closesocket(server_fd);
470 if (ff_socket_nonblock(server_fd, 1) < 0)
471 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
476 /* start all multicast streams */
477 static void start_multicast(void)
479 FFServerStream *stream;
482 struct sockaddr_in dest_addr = {0};
483 int default_port, stream_index;
486 for(stream = config.first_stream; stream; stream = stream->next) {
487 if (stream->is_multicast) {
488 unsigned random0 = av_lfg_get(&random_state);
489 unsigned random1 = av_lfg_get(&random_state);
490 /* open the RTP connection */
491 snprintf(session_id, sizeof(session_id), "%08x%08x",
494 /* choose a port if none given */
495 if (stream->multicast_port == 0) {
496 stream->multicast_port = default_port;
500 dest_addr.sin_family = AF_INET;
501 dest_addr.sin_addr = stream->multicast_ip;
502 dest_addr.sin_port = htons(stream->multicast_port);
504 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
505 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
509 if (open_input_stream(rtp_c, "") < 0) {
510 http_log("Could not open input stream for stream '%s'\n",
515 /* open each RTP stream */
516 for(stream_index = 0; stream_index < stream->nb_streams;
518 dest_addr.sin_port = htons(stream->multicast_port +
520 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
521 http_log("Could not open output stream '%s/streamid=%d'\n",
522 stream->filename, stream_index);
527 rtp_c->state = HTTPSTATE_SEND_DATA;
532 /* main loop of the HTTP server */
533 static int http_server(void)
535 int server_fd = 0, rtsp_server_fd = 0;
537 struct pollfd *poll_table, *poll_entry;
538 HTTPContext *c, *c_next;
540 if(!(poll_table = av_mallocz_array(config.nb_max_http_connections + 2, sizeof(*poll_table)))) {
541 http_log("Impossible to allocate a poll table handling %d connections.\n", config.nb_max_http_connections);
545 if (config.http_addr.sin_port) {
546 server_fd = socket_open_listen(&config.http_addr);
553 if (config.rtsp_addr.sin_port) {
554 rtsp_server_fd = socket_open_listen(&config.rtsp_addr);
555 if (rtsp_server_fd < 0) {
557 closesocket(server_fd);
562 if (!rtsp_server_fd && !server_fd) {
563 http_log("HTTP and RTSP disabled.\n");
568 http_log("FFserver started.\n");
570 start_children(config.first_feed);
575 poll_entry = poll_table;
577 poll_entry->fd = server_fd;
578 poll_entry->events = POLLIN;
581 if (rtsp_server_fd) {
582 poll_entry->fd = rtsp_server_fd;
583 poll_entry->events = POLLIN;
587 /* wait for events on each HTTP handle */
594 case HTTPSTATE_SEND_HEADER:
595 case RTSPSTATE_SEND_REPLY:
596 case RTSPSTATE_SEND_PACKET:
597 c->poll_entry = poll_entry;
599 poll_entry->events = POLLOUT;
602 case HTTPSTATE_SEND_DATA_HEADER:
603 case HTTPSTATE_SEND_DATA:
604 case HTTPSTATE_SEND_DATA_TRAILER:
605 if (!c->is_packetized) {
606 /* for TCP, we output as much as we can
607 * (may need to put a limit) */
608 c->poll_entry = poll_entry;
610 poll_entry->events = POLLOUT;
613 /* when ffserver is doing the timing, we work by
614 looking at which packet needs to be sent every
616 /* one tick wait XXX: 10 ms assumed */
621 case HTTPSTATE_WAIT_REQUEST:
622 case HTTPSTATE_RECEIVE_DATA:
623 case HTTPSTATE_WAIT_FEED:
624 case RTSPSTATE_WAIT_REQUEST:
625 /* need to catch errors */
626 c->poll_entry = poll_entry;
628 poll_entry->events = POLLIN;/* Maybe this will work */
632 c->poll_entry = NULL;
638 /* wait for an event on one connection. We poll at least every
639 second to handle timeouts */
641 ret = poll(poll_table, poll_entry - poll_table, delay);
642 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
643 ff_neterrno() != AVERROR(EINTR)) {
649 cur_time = av_gettime() / 1000;
651 if (need_to_start_children) {
652 need_to_start_children = 0;
653 start_children(config.first_feed);
656 /* now handle the events */
657 for(c = first_http_ctx; c; c = c_next) {
659 if (handle_connection(c) < 0) {
661 /* close and free the connection */
666 poll_entry = poll_table;
668 /* new HTTP connection request ? */
669 if (poll_entry->revents & POLLIN)
670 new_connection(server_fd, 0);
673 if (rtsp_server_fd) {
674 /* new RTSP connection request ? */
675 if (poll_entry->revents & POLLIN)
676 new_connection(rtsp_server_fd, 1);
681 /* start waiting for a new HTTP/RTSP request */
682 static void start_wait_request(HTTPContext *c, int is_rtsp)
684 c->buffer_ptr = c->buffer;
685 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
688 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
689 c->state = RTSPSTATE_WAIT_REQUEST;
691 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
692 c->state = HTTPSTATE_WAIT_REQUEST;
696 static void http_send_too_busy_reply(int fd)
699 int len = snprintf(buffer, sizeof(buffer),
700 "HTTP/1.0 503 Server too busy\r\n"
701 "Content-type: text/html\r\n"
703 "<html><head><title>Too busy</title></head><body>\r\n"
704 "<p>The server is too busy to serve your request at this time.</p>\r\n"
705 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
706 "</body></html>\r\n",
707 nb_connections, config.nb_max_connections);
708 av_assert0(len < sizeof(buffer));
709 if (send(fd, buffer, len, 0) < len)
710 av_log(NULL, AV_LOG_WARNING, "Could not send too-busy reply, send() failed\n");
714 static void new_connection(int server_fd, int is_rtsp)
716 struct sockaddr_in from_addr;
719 HTTPContext *c = NULL;
721 len = sizeof(from_addr);
722 fd = accept(server_fd, (struct sockaddr *)&from_addr,
725 http_log("error during accept %s\n", strerror(errno));
728 if (ff_socket_nonblock(fd, 1) < 0)
729 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
731 if (nb_connections >= config.nb_max_connections) {
732 http_send_too_busy_reply(fd);
736 /* add a new connection */
737 c = av_mallocz(sizeof(HTTPContext));
742 c->poll_entry = NULL;
743 c->from_addr = from_addr;
744 c->buffer_size = IOBUFFER_INIT_SIZE;
745 c->buffer = av_malloc(c->buffer_size);
749 c->next = first_http_ctx;
753 start_wait_request(c, is_rtsp);
759 av_freep(&c->buffer);
765 static void close_connection(HTTPContext *c)
767 HTTPContext **cp, *c1;
769 AVFormatContext *ctx;
773 /* remove connection from list */
774 cp = &first_http_ctx;
783 /* remove references, if any (XXX: do it faster) */
784 for(c1 = first_http_ctx; c1; c1 = c1->next) {
789 /* remove connection associated resources */
793 /* close each frame parser */
794 for(i=0;i<c->fmt_in->nb_streams;i++) {
795 st = c->fmt_in->streams[i];
796 if (st->codec->codec)
797 avcodec_close(st->codec);
799 avformat_close_input(&c->fmt_in);
802 /* free RTP output streams if any */
805 nb_streams = c->stream->nb_streams;
807 for(i=0;i<nb_streams;i++) {
810 av_write_trailer(ctx);
811 av_dict_free(&ctx->metadata);
812 av_freep(&ctx->streams[0]);
815 h = c->rtp_handles[i];
822 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
825 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
826 av_write_trailer(ctx);
827 av_freep(&c->pb_buffer);
828 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
833 for(i=0; i<ctx->nb_streams; i++)
834 av_freep(&ctx->streams[i]);
835 av_freep(&ctx->streams);
836 av_freep(&ctx->priv_data);
838 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
839 current_bandwidth -= c->stream->bandwidth;
841 /* signal that there is no feed if we are the feeder socket */
842 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
843 c->stream->feed_opened = 0;
847 av_freep(&c->pb_buffer);
848 av_freep(&c->packet_buffer);
849 av_freep(&c->buffer);
854 static int handle_connection(HTTPContext *c)
859 case HTTPSTATE_WAIT_REQUEST:
860 case RTSPSTATE_WAIT_REQUEST:
862 if ((c->timeout - cur_time) < 0)
864 if (c->poll_entry->revents & (POLLERR | POLLHUP))
867 /* no need to read if no events */
868 if (!(c->poll_entry->revents & POLLIN))
872 len = recv(c->fd, c->buffer_ptr, 1, 0);
874 if (ff_neterrno() != AVERROR(EAGAIN) &&
875 ff_neterrno() != AVERROR(EINTR))
877 } else if (len == 0) {
880 /* search for end of request. */
882 c->buffer_ptr += len;
884 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
885 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
886 /* request found : parse it and reply */
887 if (c->state == HTTPSTATE_WAIT_REQUEST) {
888 ret = http_parse_request(c);
890 ret = rtsp_parse_request(c);
894 } else if (ptr >= c->buffer_end) {
895 /* request too long: cannot do anything */
897 } else goto read_loop;
901 case HTTPSTATE_SEND_HEADER:
902 if (c->poll_entry->revents & (POLLERR | POLLHUP))
905 /* no need to write if no events */
906 if (!(c->poll_entry->revents & POLLOUT))
908 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
910 if (ff_neterrno() != AVERROR(EAGAIN) &&
911 ff_neterrno() != AVERROR(EINTR)) {
912 goto close_connection;
915 c->buffer_ptr += len;
917 c->stream->bytes_served += len;
918 c->data_count += len;
919 if (c->buffer_ptr >= c->buffer_end) {
920 av_freep(&c->pb_buffer);
924 /* all the buffer was sent : synchronize to the incoming
926 c->state = HTTPSTATE_SEND_DATA_HEADER;
927 c->buffer_ptr = c->buffer_end = c->buffer;
932 case HTTPSTATE_SEND_DATA:
933 case HTTPSTATE_SEND_DATA_HEADER:
934 case HTTPSTATE_SEND_DATA_TRAILER:
935 /* for packetized output, we consider we can always write (the
936 input streams set the speed). It may be better to verify
937 that we do not rely too much on the kernel queues */
938 if (!c->is_packetized) {
939 if (c->poll_entry->revents & (POLLERR | POLLHUP))
942 /* no need to read if no events */
943 if (!(c->poll_entry->revents & POLLOUT))
946 if (http_send_data(c) < 0)
948 /* close connection if trailer sent */
949 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
952 case HTTPSTATE_RECEIVE_DATA:
953 /* no need to read if no events */
954 if (c->poll_entry->revents & (POLLERR | POLLHUP))
956 if (!(c->poll_entry->revents & POLLIN))
958 if (http_receive_data(c) < 0)
961 case HTTPSTATE_WAIT_FEED:
962 /* no need to read if no events */
963 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
966 /* nothing to do, we'll be waken up by incoming feed packets */
969 case RTSPSTATE_SEND_REPLY:
970 if (c->poll_entry->revents & (POLLERR | POLLHUP))
971 goto close_connection;
972 /* no need to write if no events */
973 if (!(c->poll_entry->revents & POLLOUT))
975 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
977 if (ff_neterrno() != AVERROR(EAGAIN) &&
978 ff_neterrno() != AVERROR(EINTR)) {
979 goto close_connection;
982 c->buffer_ptr += len;
983 c->data_count += len;
984 if (c->buffer_ptr >= c->buffer_end) {
985 /* all the buffer was sent : wait for a new request */
986 av_freep(&c->pb_buffer);
987 start_wait_request(c, 1);
991 case RTSPSTATE_SEND_PACKET:
992 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
993 av_freep(&c->packet_buffer);
996 /* no need to write if no events */
997 if (!(c->poll_entry->revents & POLLOUT))
999 len = send(c->fd, c->packet_buffer_ptr,
1000 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1002 if (ff_neterrno() != AVERROR(EAGAIN) &&
1003 ff_neterrno() != AVERROR(EINTR)) {
1004 /* error : close connection */
1005 av_freep(&c->packet_buffer);
1009 c->packet_buffer_ptr += len;
1010 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1011 /* all the buffer was sent : wait for a new request */
1012 av_freep(&c->packet_buffer);
1013 c->state = RTSPSTATE_WAIT_REQUEST;
1017 case HTTPSTATE_READY:
1026 av_freep(&c->pb_buffer);
1030 static int extract_rates(char *rates, int ratelen, const char *request)
1034 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1035 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1036 const char *q = p + 7;
1038 while (*q && *q != '\n' && av_isspace(*q))
1041 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1047 memset(rates, 0xff, ratelen);
1050 while (*q && *q != '\n' && *q != ':')
1053 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1057 if (stream_no < ratelen && stream_no >= 0)
1058 rates[stream_no] = rate_no;
1060 while (*q && *q != '\n' && !av_isspace(*q))
1067 p = strchr(p, '\n');
1077 static int find_stream_in_feed(FFServerStream *feed, AVCodecContext *codec, int bit_rate)
1080 int best_bitrate = 100000000;
1083 for (i = 0; i < feed->nb_streams; i++) {
1084 AVCodecContext *feed_codec = feed->streams[i]->codec;
1086 if (feed_codec->codec_id != codec->codec_id ||
1087 feed_codec->sample_rate != codec->sample_rate ||
1088 feed_codec->width != codec->width ||
1089 feed_codec->height != codec->height)
1092 /* Potential stream */
1094 /* We want the fastest stream less than bit_rate, or the slowest
1095 * faster than bit_rate
1098 if (feed_codec->bit_rate <= bit_rate) {
1099 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1100 best_bitrate = feed_codec->bit_rate;
1104 if (feed_codec->bit_rate < best_bitrate) {
1105 best_bitrate = feed_codec->bit_rate;
1114 static int modify_current_stream(HTTPContext *c, char *rates)
1117 FFServerStream *req = c->stream;
1118 int action_required = 0;
1120 /* Not much we can do for a feed */
1124 for (i = 0; i < req->nb_streams; i++) {
1125 AVCodecContext *codec = req->streams[i]->codec;
1129 c->switch_feed_streams[i] = req->feed_streams[i];
1132 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1135 /* Wants off or slow */
1136 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1138 /* This doesn't work well when it turns off the only stream! */
1139 c->switch_feed_streams[i] = -2;
1140 c->feed_streams[i] = -2;
1145 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1146 action_required = 1;
1149 return action_required;
1152 static void get_word(char *buf, int buf_size, const char **pp)
1158 p += strspn(p, SPACE_CHARS);
1160 while (!av_isspace(*p) && *p != '\0') {
1161 if ((q - buf) < buf_size - 1)
1170 static FFServerIPAddressACL* parse_dynamic_acl(FFServerStream *stream, HTTPContext *c)
1175 FFServerIPAddressACL *acl = NULL;
1179 f = fopen(stream->dynamic_acl, "r");
1181 perror(stream->dynamic_acl);
1185 acl = av_mallocz(sizeof(FFServerIPAddressACL));
1189 if (fgets(line, sizeof(line), f) == NULL)
1193 while (av_isspace(*p))
1195 if (*p == '\0' || *p == '#')
1197 ffserver_get_arg(cmd, sizeof(cmd), &p);
1199 if (!av_strcasecmp(cmd, "ACL"))
1200 ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1207 static void free_acl_list(FFServerIPAddressACL *in_acl)
1209 FFServerIPAddressACL *pacl, *pacl2;
1219 static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c)
1221 enum FFServerIPAddressAction last_action = IP_DENY;
1222 FFServerIPAddressACL *acl;
1223 struct in_addr *src = &c->from_addr.sin_addr;
1224 unsigned long src_addr = src->s_addr;
1226 for (acl = in_acl; acl; acl = acl->next) {
1227 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1228 return (acl->action == IP_ALLOW) ? 1 : 0;
1229 last_action = acl->action;
1232 /* Nothing matched, so return not the last action */
1233 return (last_action == IP_DENY) ? 1 : 0;
1236 static int validate_acl(FFServerStream *stream, HTTPContext *c)
1239 FFServerIPAddressACL *acl;
1241 /* if stream->acl is null validate_acl_list will return 1 */
1242 ret = validate_acl_list(stream->acl, c);
1244 if (stream->dynamic_acl[0]) {
1245 acl = parse_dynamic_acl(stream, c);
1247 ret = validate_acl_list(acl, c);
1255 /* compute the real filename of a file by matching it without its
1256 extensions to all the stream's filenames */
1257 static void compute_real_filename(char *filename, int max_size)
1262 FFServerStream *stream;
1264 /* compute filename by matching without the file extensions */
1265 av_strlcpy(file1, filename, sizeof(file1));
1266 p = strrchr(file1, '.');
1269 for(stream = config.first_stream; stream; stream = stream->next) {
1270 av_strlcpy(file2, stream->filename, sizeof(file2));
1271 p = strrchr(file2, '.');
1274 if (!strcmp(file1, file2)) {
1275 av_strlcpy(filename, stream->filename, max_size);
1290 /* parse HTTP request and prepare header */
1291 static int http_parse_request(HTTPContext *c)
1295 enum RedirType redir_type;
1297 char info[1024], filename[1024];
1301 const char *mime_type;
1302 FFServerStream *stream;
1305 const char *useragent = 0;
1308 get_word(cmd, sizeof(cmd), &p);
1309 av_strlcpy(c->method, cmd, sizeof(c->method));
1311 if (!strcmp(cmd, "GET"))
1313 else if (!strcmp(cmd, "POST"))
1318 get_word(url, sizeof(url), &p);
1319 av_strlcpy(c->url, url, sizeof(c->url));
1321 get_word(protocol, sizeof(protocol), (const char **)&p);
1322 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1325 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1328 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1330 /* find the filename and the optional info string in the request */
1331 p1 = strchr(url, '?');
1333 av_strlcpy(info, p1, sizeof(info));
1338 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1340 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1341 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1343 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1347 p = strchr(p, '\n');
1354 redir_type = REDIR_NONE;
1355 if (av_match_ext(filename, "asx")) {
1356 redir_type = REDIR_ASX;
1357 filename[strlen(filename)-1] = 'f';
1358 } else if (av_match_ext(filename, "asf") &&
1359 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) {
1360 /* if this isn't WMP or lookalike, return the redirector file */
1361 redir_type = REDIR_ASF;
1362 } else if (av_match_ext(filename, "rpm,ram")) {
1363 redir_type = REDIR_RAM;
1364 strcpy(filename + strlen(filename)-2, "m");
1365 } else if (av_match_ext(filename, "rtsp")) {
1366 redir_type = REDIR_RTSP;
1367 compute_real_filename(filename, sizeof(filename) - 1);
1368 } else if (av_match_ext(filename, "sdp")) {
1369 redir_type = REDIR_SDP;
1370 compute_real_filename(filename, sizeof(filename) - 1);
1373 // "redirect" / request to index.html
1374 if (!strlen(filename))
1375 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1377 stream = config.first_stream;
1379 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1381 stream = stream->next;
1384 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1385 http_log("File '%s' not found\n", url);
1390 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1391 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1393 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1394 c->http_error = 301;
1396 snprintf(q, c->buffer_size,
1397 "HTTP/1.0 301 Moved\r\n"
1399 "Content-type: text/html\r\n"
1401 "<html><head><title>Moved</title></head><body>\r\n"
1402 "You should be <a href=\"%s\">redirected</a>.\r\n"
1403 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1405 /* prepare output buffer */
1406 c->buffer_ptr = c->buffer;
1408 c->state = HTTPSTATE_SEND_HEADER;
1412 /* If this is WMP, get the rate information */
1413 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1414 if (modify_current_stream(c, ratebuf)) {
1415 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1416 if (c->switch_feed_streams[i] >= 0)
1417 c->switch_feed_streams[i] = -1;
1422 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1423 current_bandwidth += stream->bandwidth;
1425 /* If already streaming this feed, do not let start another feeder. */
1426 if (stream->feed_opened) {
1427 snprintf(msg, sizeof(msg), "This feed is already being received.");
1428 http_log("Feed '%s' already being received\n", stream->feed_filename);
1432 if (c->post == 0 && config.max_bandwidth < current_bandwidth) {
1433 c->http_error = 503;
1435 snprintf(q, c->buffer_size,
1436 "HTTP/1.0 503 Server too busy\r\n"
1437 "Content-type: text/html\r\n"
1439 "<html><head><title>Too busy</title></head><body>\r\n"
1440 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1441 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1442 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1443 "</body></html>\r\n", current_bandwidth, config.max_bandwidth);
1445 /* prepare output buffer */
1446 c->buffer_ptr = c->buffer;
1448 c->state = HTTPSTATE_SEND_HEADER;
1452 if (redir_type != REDIR_NONE) {
1453 const char *hostinfo = 0;
1455 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1456 if (av_strncasecmp(p, "Host:", 5) == 0) {
1460 p = strchr(p, '\n');
1471 while (av_isspace(*hostinfo))
1474 eoh = strchr(hostinfo, '\n');
1476 if (eoh[-1] == '\r')
1479 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1480 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1481 hostbuf[eoh - hostinfo] = 0;
1483 c->http_error = 200;
1485 switch(redir_type) {
1487 snprintf(q, c->buffer_size,
1488 "HTTP/1.0 200 ASX Follows\r\n"
1489 "Content-type: video/x-ms-asf\r\n"
1491 "<ASX Version=\"3\">\r\n"
1492 //"<!-- Autogenerated by ffserver -->\r\n"
1493 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1494 "</ASX>\r\n", hostbuf, filename, info);
1498 snprintf(q, c->buffer_size,
1499 "HTTP/1.0 200 RAM Follows\r\n"
1500 "Content-type: audio/x-pn-realaudio\r\n"
1502 "# Autogenerated by ffserver\r\n"
1503 "http://%s/%s%s\r\n", hostbuf, filename, info);
1507 snprintf(q, c->buffer_size,
1508 "HTTP/1.0 200 ASF Redirect follows\r\n"
1509 "Content-type: video/x-ms-asf\r\n"
1512 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1517 char hostname[256], *p;
1518 /* extract only hostname */
1519 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1520 p = strrchr(hostname, ':');
1523 snprintf(q, c->buffer_size,
1524 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1525 /* XXX: incorrect MIME type ? */
1526 "Content-type: application/x-rtsp\r\n"
1528 "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
1537 struct sockaddr_in my_addr;
1539 snprintf(q, c->buffer_size,
1540 "HTTP/1.0 200 OK\r\n"
1541 "Content-type: application/sdp\r\n"
1545 len = sizeof(my_addr);
1547 /* XXX: Should probably fail? */
1548 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1549 http_log("getsockname() failed\n");
1551 /* XXX: should use a dynamic buffer */
1552 sdp_data_size = prepare_sdp_description(stream,
1555 if (sdp_data_size > 0) {
1556 memcpy(q, sdp_data, sdp_data_size);
1568 /* prepare output buffer */
1569 c->buffer_ptr = c->buffer;
1571 c->state = HTTPSTATE_SEND_HEADER;
1577 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1581 stream->conns_served++;
1583 /* XXX: add there authenticate and IP match */
1586 /* if post, it means a feed is being sent */
1587 if (!stream->is_feed) {
1588 /* However it might be a status report from WMP! Let us log the
1589 * data as it might come handy one day. */
1590 const char *logline = 0;
1593 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1594 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1598 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1599 client_id = strtol(p + 18, 0, 10);
1600 p = strchr(p, '\n');
1608 char *eol = strchr(logline, '\n');
1613 if (eol[-1] == '\r')
1615 http_log("%.*s\n", (int) (eol - logline), logline);
1616 c->suppress_log = 1;
1621 http_log("\nGot request:\n%s\n", c->buffer);
1624 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1627 /* Now we have to find the client_id */
1628 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1629 if (wmpc->wmp_client_id == client_id)
1633 if (wmpc && modify_current_stream(wmpc, ratebuf))
1634 wmpc->switch_pending = 1;
1637 snprintf(msg, sizeof(msg), "POST command not handled");
1641 if (http_start_receive_data(c) < 0) {
1642 snprintf(msg, sizeof(msg), "could not open feed");
1646 c->state = HTTPSTATE_RECEIVE_DATA;
1651 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1652 http_log("\nGot request:\n%s\n", c->buffer);
1655 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1658 /* open input stream */
1659 if (open_input_stream(c, info) < 0) {
1660 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1664 /* prepare HTTP header */
1666 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1667 mime_type = c->stream->fmt->mime_type;
1669 mime_type = "application/x-octet-stream";
1670 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1672 /* for asf, we need extra headers */
1673 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1674 /* Need to allocate a client id */
1676 c->wmp_client_id = av_lfg_get(&random_state);
1678 av_strlcatf(c->buffer, c->buffer_size, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id);
1680 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1681 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1682 q = c->buffer + strlen(c->buffer);
1684 /* prepare output buffer */
1686 c->buffer_ptr = c->buffer;
1688 c->state = HTTPSTATE_SEND_HEADER;
1691 c->http_error = 404;
1694 snprintf(q, c->buffer_size,
1695 "HTTP/1.0 404 Not Found\r\n"
1696 "Content-type: text/html\r\n"
1699 "<head><title>404 Not Found</title></head>\n"
1703 /* prepare output buffer */
1704 c->buffer_ptr = c->buffer;
1706 c->state = HTTPSTATE_SEND_HEADER;
1710 c->http_error = 200; /* horrible : we use this value to avoid
1711 going to the send data state */
1712 c->state = HTTPSTATE_SEND_HEADER;
1716 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1718 static const char suffix[] = " kMGTP";
1721 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1723 avio_printf(pb, "%"PRId64"%c", count, *s);
1726 static void compute_status(HTTPContext *c)
1729 FFServerStream *stream;
1735 if (avio_open_dyn_buf(&pb) < 0) {
1736 /* XXX: return an error ? */
1737 c->buffer_ptr = c->buffer;
1738 c->buffer_end = c->buffer;
1742 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1743 avio_printf(pb, "Content-type: text/html\r\n");
1744 avio_printf(pb, "Pragma: no-cache\r\n");
1745 avio_printf(pb, "\r\n");
1747 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1748 if (c->stream->feed_filename[0])
1749 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1750 avio_printf(pb, "</head>\n<body>");
1751 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1753 avio_printf(pb, "<h2>Available Streams</h2>\n");
1754 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1755 avio_printf(pb, "<tr><th valign=top>Path<th align=left>Served<br>Conns<th><br>bytes<th valign=top>Format<th>Bit rate<br>kbits/s<th align=left>Video<br>kbits/s<th><br>Codec<th align=left>Audio<br>kbits/s<th><br>Codec<th align=left valign=top>Feed\n");
1756 stream = config.first_stream;
1758 char sfilename[1024];
1761 if (stream->feed != stream) {
1762 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1763 eosf = sfilename + strlen(sfilename);
1764 if (eosf - sfilename >= 4) {
1765 if (strcmp(eosf - 4, ".asf") == 0)
1766 strcpy(eosf - 4, ".asx");
1767 else if (strcmp(eosf - 3, ".rm") == 0)
1768 strcpy(eosf - 3, ".ram");
1769 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1770 /* generate a sample RTSP director if
1771 unicast. Generate an SDP redirector if
1773 eosf = strrchr(sfilename, '.');
1775 eosf = sfilename + strlen(sfilename);
1776 if (stream->is_multicast)
1777 strcpy(eosf, ".sdp");
1779 strcpy(eosf, ".rtsp");
1783 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1784 sfilename, stream->filename);
1785 avio_printf(pb, "<td align=right> %d <td align=right> ",
1786 stream->conns_served);
1787 fmt_bytecount(pb, stream->bytes_served);
1788 switch(stream->stream_type) {
1789 case STREAM_TYPE_LIVE: {
1790 int audio_bit_rate = 0;
1791 int video_bit_rate = 0;
1792 const char *audio_codec_name = "";
1793 const char *video_codec_name = "";
1794 const char *audio_codec_name_extra = "";
1795 const char *video_codec_name_extra = "";
1797 for(i=0;i<stream->nb_streams;i++) {
1798 AVStream *st = stream->streams[i];
1799 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1800 switch(st->codec->codec_type) {
1801 case AVMEDIA_TYPE_AUDIO:
1802 audio_bit_rate += st->codec->bit_rate;
1804 if (*audio_codec_name)
1805 audio_codec_name_extra = "...";
1806 audio_codec_name = codec->name;
1809 case AVMEDIA_TYPE_VIDEO:
1810 video_bit_rate += st->codec->bit_rate;
1812 if (*video_codec_name)
1813 video_codec_name_extra = "...";
1814 video_codec_name = codec->name;
1817 case AVMEDIA_TYPE_DATA:
1818 video_bit_rate += st->codec->bit_rate;
1824 avio_printf(pb, "<td align=center> %s <td align=right> %d <td align=right> %d <td> %s %s <td align=right> %d <td> %s %s",
1827 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1828 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1830 avio_printf(pb, "<td>%s", stream->feed->filename);
1832 avio_printf(pb, "<td>%s", stream->feed_filename);
1833 avio_printf(pb, "\n");
1837 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1841 stream = stream->next;
1843 avio_printf(pb, "</table>\n");
1845 stream = config.first_stream;
1847 if (stream->feed == stream) {
1848 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1850 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1857 /* This is somewhat linux specific I guess */
1858 snprintf(ps_cmd, sizeof(ps_cmd),
1859 "ps -o \"%%cpu,cputime\" --no-headers %d",
1862 pid_stat = popen(ps_cmd, "r");
1867 if (fscanf(pid_stat, "%9s %63s", cpuperc,
1869 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1877 avio_printf(pb, "<p>");
1879 avio_printf(pb, "<table cellspacing=0 cellpadding=4><tr><th>Stream<th>type<th>kbits/s<th align=left>codec<th align=left>Parameters\n");
1881 for (i = 0; i < stream->nb_streams; i++) {
1882 AVStream *st = stream->streams[i];
1883 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1884 const char *type = "unknown";
1885 char parameters[64];
1889 switch(st->codec->codec_type) {
1890 case AVMEDIA_TYPE_AUDIO:
1892 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1894 case AVMEDIA_TYPE_VIDEO:
1896 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1897 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1902 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1903 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1905 avio_printf(pb, "</table>\n");
1908 stream = stream->next;
1911 /* connection status */
1912 avio_printf(pb, "<h2>Connection Status</h2>\n");
1914 avio_printf(pb, "Number of connections: %d / %d<br>\n",
1915 nb_connections, config.nb_max_connections);
1917 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1918 current_bandwidth, config.max_bandwidth);
1920 avio_printf(pb, "<table>\n");
1921 avio_printf(pb, "<tr><th>#<th>File<th>IP<th>Proto<th>State<th>Target bits/sec<th>Actual bits/sec<th>Bytes transferred\n");
1922 c1 = first_http_ctx;
1930 for (j = 0; j < c1->stream->nb_streams; j++) {
1931 if (!c1->stream->feed)
1932 bitrate += c1->stream->streams[j]->codec->bit_rate;
1933 else if (c1->feed_streams[j] >= 0)
1934 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1939 p = inet_ntoa(c1->from_addr.sin_addr);
1940 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
1942 c1->stream ? c1->stream->filename : "",
1943 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1946 http_state[c1->state]);
1947 fmt_bytecount(pb, bitrate);
1948 avio_printf(pb, "<td align=right>");
1949 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1950 avio_printf(pb, "<td align=right>");
1951 fmt_bytecount(pb, c1->data_count);
1952 avio_printf(pb, "\n");
1955 avio_printf(pb, "</table>\n");
1960 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
1961 avio_printf(pb, "</body>\n</html>\n");
1963 len = avio_close_dyn_buf(pb, &c->pb_buffer);
1964 c->buffer_ptr = c->pb_buffer;
1965 c->buffer_end = c->pb_buffer + len;
1968 static int open_input_stream(HTTPContext *c, const char *info)
1971 char input_filename[1024];
1972 AVFormatContext *s = NULL;
1973 int buf_size, i, ret;
1976 /* find file name */
1977 if (c->stream->feed) {
1978 strcpy(input_filename, c->stream->feed->feed_filename);
1979 buf_size = FFM_PACKET_SIZE;
1980 /* compute position (absolute time) */
1981 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
1982 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
1983 http_log("Invalid date specification '%s' for stream\n", buf);
1986 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
1987 int prebuffer = strtol(buf, 0, 10);
1988 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
1990 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
1992 strcpy(input_filename, c->stream->feed_filename);
1994 /* compute position (relative time) */
1995 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
1996 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
1997 http_log("Invalid date specification '%s' for stream\n", buf);
2003 if (!input_filename[0]) {
2004 http_log("No filename was specified for stream\n");
2005 return AVERROR(EINVAL);
2009 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2010 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2014 /* set buffer size */
2015 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2017 s->flags |= AVFMT_FLAG_GENPTS;
2019 if (strcmp(s->iformat->name, "ffm") &&
2020 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2021 http_log("Could not find stream info for input '%s'\n", input_filename);
2022 avformat_close_input(&s);
2026 /* choose stream as clock source (we favor the video stream if
2027 * present) for packet sending */
2028 c->pts_stream_index = 0;
2029 for(i=0;i<c->stream->nb_streams;i++) {
2030 if (c->pts_stream_index == 0 &&
2031 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2032 c->pts_stream_index = i;
2036 if (c->fmt_in->iformat->read_seek)
2037 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2038 /* set the start time (needed for maxtime and RTP packet timing) */
2039 c->start_time = cur_time;
2040 c->first_pts = AV_NOPTS_VALUE;
2044 /* return the server clock (in us) */
2045 static int64_t get_server_clock(HTTPContext *c)
2047 /* compute current pts value from system time */
2048 return (cur_time - c->start_time) * 1000;
2051 /* return the estimated time at which the current packet must be sent
2053 static int64_t get_packet_send_clock(HTTPContext *c)
2055 int bytes_left, bytes_sent, frame_bytes;
2057 frame_bytes = c->cur_frame_bytes;
2058 if (frame_bytes <= 0)
2061 bytes_left = c->buffer_end - c->buffer_ptr;
2062 bytes_sent = frame_bytes - bytes_left;
2063 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2068 static int http_prepare_data(HTTPContext *c)
2071 AVFormatContext *ctx;
2073 av_freep(&c->pb_buffer);
2075 case HTTPSTATE_SEND_DATA_HEADER:
2076 ctx = avformat_alloc_context();
2079 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2080 c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams, sizeof(AVStream *));
2082 for(i=0;i<c->stream->nb_streams;i++) {
2084 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2085 /* if file or feed, then just take streams from FFServerStream struct */
2086 if (!c->stream->feed ||
2087 c->stream->feed == c->stream)
2088 src = c->stream->streams[i];
2090 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2092 *(c->fmt_ctx.streams[i]) = *src;
2093 c->fmt_ctx.streams[i]->priv_data = 0;
2094 /* XXX: should be done in AVStream, not in codec */
2095 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2097 /* set output format parameters */
2098 c->fmt_ctx.oformat = c->stream->fmt;
2099 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2101 c->got_key_frame = 0;
2103 /* prepare header and save header data in a stream */
2104 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2105 /* XXX: potential leak */
2108 c->fmt_ctx.pb->seekable = 0;
2111 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2112 * Default value from FFmpeg
2113 * Try to set it using configuration option
2115 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2117 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2118 http_log("Error writing output header for stream '%s': %s\n",
2119 c->stream->filename, av_err2str(ret));
2122 av_dict_free(&c->fmt_ctx.metadata);
2124 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2125 c->buffer_ptr = c->pb_buffer;
2126 c->buffer_end = c->pb_buffer + len;
2128 c->state = HTTPSTATE_SEND_DATA;
2129 c->last_packet_sent = 0;
2131 case HTTPSTATE_SEND_DATA:
2132 /* find a new packet */
2133 /* read a packet from the input stream */
2134 if (c->stream->feed)
2135 ffm_set_write_index(c->fmt_in,
2136 c->stream->feed->feed_write_index,
2137 c->stream->feed->feed_size);
2139 if (c->stream->max_time &&
2140 c->stream->max_time + c->start_time - cur_time < 0)
2141 /* We have timed out */
2142 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2146 ret = av_read_frame(c->fmt_in, &pkt);
2148 if (c->stream->feed) {
2149 /* if coming from feed, it means we reached the end of the
2150 ffm file, so must wait for more data */
2151 c->state = HTTPSTATE_WAIT_FEED;
2152 return 1; /* state changed */
2153 } else if (ret == AVERROR(EAGAIN)) {
2154 /* input not ready, come back later */
2157 if (c->stream->loop) {
2158 avformat_close_input(&c->fmt_in);
2159 if (open_input_stream(c, "") < 0)
2164 /* must send trailer now because EOF or error */
2165 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2169 int source_index = pkt.stream_index;
2170 /* update first pts if needed */
2171 if (c->first_pts == AV_NOPTS_VALUE) {
2172 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2173 c->start_time = cur_time;
2175 /* send it to the appropriate stream */
2176 if (c->stream->feed) {
2177 /* if coming from a feed, select the right stream */
2178 if (c->switch_pending) {
2179 c->switch_pending = 0;
2180 for(i=0;i<c->stream->nb_streams;i++) {
2181 if (c->switch_feed_streams[i] == pkt.stream_index)
2182 if (pkt.flags & AV_PKT_FLAG_KEY)
2183 c->switch_feed_streams[i] = -1;
2184 if (c->switch_feed_streams[i] >= 0)
2185 c->switch_pending = 1;
2188 for(i=0;i<c->stream->nb_streams;i++) {
2189 if (c->stream->feed_streams[i] == pkt.stream_index) {
2190 AVStream *st = c->fmt_in->streams[source_index];
2191 pkt.stream_index = i;
2192 if (pkt.flags & AV_PKT_FLAG_KEY &&
2193 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2194 c->stream->nb_streams == 1))
2195 c->got_key_frame = 1;
2196 if (!c->stream->send_on_key || c->got_key_frame)
2201 AVCodecContext *codec;
2202 AVStream *ist, *ost;
2204 ist = c->fmt_in->streams[source_index];
2205 /* specific handling for RTP: we use several
2206 * output streams (one for each RTP connection).
2207 * XXX: need more abstract handling */
2208 if (c->is_packetized) {
2209 /* compute send time and duration */
2210 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2211 c->cur_pts -= c->first_pts;
2212 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2213 /* find RTP context */
2214 c->packet_stream_index = pkt.stream_index;
2215 ctx = c->rtp_ctx[c->packet_stream_index];
2217 av_free_packet(&pkt);
2220 codec = ctx->streams[0]->codec;
2221 /* only one stream per RTP connection */
2222 pkt.stream_index = 0;
2226 codec = ctx->streams[pkt.stream_index]->codec;
2229 if (c->is_packetized) {
2230 int max_packet_size;
2231 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2232 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2234 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2235 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2237 ret = avio_open_dyn_buf(&ctx->pb);
2240 /* XXX: potential leak */
2243 ost = ctx->streams[pkt.stream_index];
2245 ctx->pb->seekable = 0;
2246 if (pkt.dts != AV_NOPTS_VALUE)
2247 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2248 if (pkt.pts != AV_NOPTS_VALUE)
2249 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2250 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2251 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2252 http_log("Error writing frame to output for stream '%s': %s\n",
2253 c->stream->filename, av_err2str(ret));
2254 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2257 av_freep(&c->pb_buffer);
2258 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2259 c->cur_frame_bytes = len;
2260 c->buffer_ptr = c->pb_buffer;
2261 c->buffer_end = c->pb_buffer + len;
2263 codec->frame_number++;
2265 av_free_packet(&pkt);
2269 av_free_packet(&pkt);
2274 case HTTPSTATE_SEND_DATA_TRAILER:
2275 /* last packet test ? */
2276 if (c->last_packet_sent || c->is_packetized)
2279 /* prepare header */
2280 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2281 /* XXX: potential leak */
2284 c->fmt_ctx.pb->seekable = 0;
2285 av_write_trailer(ctx);
2286 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2287 c->buffer_ptr = c->pb_buffer;
2288 c->buffer_end = c->pb_buffer + len;
2290 c->last_packet_sent = 1;
2296 /* should convert the format at the same time */
2297 /* send data starting at c->buffer_ptr to the output connection
2298 * (either UDP or TCP) */
2299 static int http_send_data(HTTPContext *c)
2304 if (c->buffer_ptr >= c->buffer_end) {
2305 ret = http_prepare_data(c);
2309 /* state change requested */
2312 if (c->is_packetized) {
2313 /* RTP data output */
2314 len = c->buffer_end - c->buffer_ptr;
2316 /* fail safe - should never happen */
2318 c->buffer_ptr = c->buffer_end;
2321 len = (c->buffer_ptr[0] << 24) |
2322 (c->buffer_ptr[1] << 16) |
2323 (c->buffer_ptr[2] << 8) |
2325 if (len > (c->buffer_end - c->buffer_ptr))
2327 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2328 /* nothing to send yet: we can wait */
2332 c->data_count += len;
2333 update_datarate(&c->datarate, c->data_count);
2335 c->stream->bytes_served += len;
2337 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2338 /* RTP packets are sent inside the RTSP TCP connection */
2340 int interleaved_index, size;
2342 HTTPContext *rtsp_c;
2345 /* if no RTSP connection left, error */
2348 /* if already sending something, then wait. */
2349 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2351 if (avio_open_dyn_buf(&pb) < 0)
2353 interleaved_index = c->packet_stream_index * 2;
2354 /* RTCP packets are sent at odd indexes */
2355 if (c->buffer_ptr[1] == 200)
2356 interleaved_index++;
2357 /* write RTSP TCP header */
2359 header[1] = interleaved_index;
2360 header[2] = len >> 8;
2362 avio_write(pb, header, 4);
2363 /* write RTP packet data */
2365 avio_write(pb, c->buffer_ptr, len);
2366 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2367 /* prepare asynchronous TCP sending */
2368 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2369 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2370 c->buffer_ptr += len;
2372 /* send everything we can NOW */
2373 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2374 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2376 rtsp_c->packet_buffer_ptr += len;
2377 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2378 /* if we could not send all the data, we will
2379 send it later, so a new state is needed to
2380 "lock" the RTSP TCP connection */
2381 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2384 /* all data has been sent */
2385 av_freep(&c->packet_buffer);
2387 /* send RTP packet directly in UDP */
2389 ffurl_write(c->rtp_handles[c->packet_stream_index],
2390 c->buffer_ptr, len);
2391 c->buffer_ptr += len;
2392 /* here we continue as we can send several packets per 10 ms slot */
2395 /* TCP data output */
2396 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2398 if (ff_neterrno() != AVERROR(EAGAIN) &&
2399 ff_neterrno() != AVERROR(EINTR))
2400 /* error : close connection */
2405 c->buffer_ptr += len;
2407 c->data_count += len;
2408 update_datarate(&c->datarate, c->data_count);
2410 c->stream->bytes_served += len;
2418 static int http_start_receive_data(HTTPContext *c)
2423 if (c->stream->feed_opened) {
2424 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2425 return AVERROR(EINVAL);
2428 /* Don't permit writing to this one */
2429 if (c->stream->readonly) {
2430 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2431 return AVERROR(EINVAL);
2435 fd = open(c->stream->feed_filename, O_RDWR);
2437 ret = AVERROR(errno);
2438 http_log("Could not open feed file '%s': %s\n",
2439 c->stream->feed_filename, strerror(errno));
2444 if (c->stream->truncate) {
2445 /* truncate feed file */
2446 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2447 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2448 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2449 ret = AVERROR(errno);
2450 http_log("Error truncating feed file '%s': %s\n",
2451 c->stream->feed_filename, strerror(errno));
2455 ret = ffm_read_write_index(fd);
2457 http_log("Error reading write index from feed file '%s': %s\n",
2458 c->stream->feed_filename, strerror(errno));
2461 c->stream->feed_write_index = ret;
2465 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2466 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2467 lseek(fd, 0, SEEK_SET);
2469 /* init buffer input */
2470 c->buffer_ptr = c->buffer;
2471 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2472 c->stream->feed_opened = 1;
2473 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2477 static int http_receive_data(HTTPContext *c)
2480 int len, loop_run = 0;
2482 while (c->chunked_encoding && !c->chunk_size &&
2483 c->buffer_end > c->buffer_ptr) {
2484 /* read chunk header, if present */
2485 len = recv(c->fd, c->buffer_ptr, 1, 0);
2488 if (ff_neterrno() != AVERROR(EAGAIN) &&
2489 ff_neterrno() != AVERROR(EINTR))
2490 /* error : close connection */
2493 } else if (len == 0) {
2494 /* end of connection : close it */
2496 } else if (c->buffer_ptr - c->buffer >= 2 &&
2497 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2498 c->chunk_size = strtol(c->buffer, 0, 16);
2499 if (c->chunk_size == 0) // end of stream
2501 c->buffer_ptr = c->buffer;
2503 } else if (++loop_run > 10) {
2504 /* no chunk header, abort */
2511 if (c->buffer_end > c->buffer_ptr) {
2512 len = recv(c->fd, c->buffer_ptr,
2513 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2515 if (ff_neterrno() != AVERROR(EAGAIN) &&
2516 ff_neterrno() != AVERROR(EINTR))
2517 /* error : close connection */
2519 } else if (len == 0)
2520 /* end of connection : close it */
2523 c->chunk_size -= len;
2524 c->buffer_ptr += len;
2525 c->data_count += len;
2526 update_datarate(&c->datarate, c->data_count);
2530 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2531 if (c->buffer[0] != 'f' ||
2532 c->buffer[1] != 'm') {
2533 http_log("Feed stream has become desynchronized -- disconnecting\n");
2538 if (c->buffer_ptr >= c->buffer_end) {
2539 FFServerStream *feed = c->stream;
2540 /* a packet has been received : write it in the store, except
2542 if (c->data_count > FFM_PACKET_SIZE) {
2543 /* XXX: use llseek or url_seek
2544 * XXX: Should probably fail? */
2545 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2546 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2548 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2549 http_log("Error writing to feed file: %s\n", strerror(errno));
2553 feed->feed_write_index += FFM_PACKET_SIZE;
2554 /* update file size */
2555 if (feed->feed_write_index > c->stream->feed_size)
2556 feed->feed_size = feed->feed_write_index;
2558 /* handle wrap around if max file size reached */
2559 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2560 feed->feed_write_index = FFM_PACKET_SIZE;
2563 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2564 http_log("Error writing index to feed file: %s\n", strerror(errno));
2568 /* wake up any waiting connections */
2569 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2570 if (c1->state == HTTPSTATE_WAIT_FEED &&
2571 c1->stream->feed == c->stream->feed)
2572 c1->state = HTTPSTATE_SEND_DATA;
2575 /* We have a header in our hands that contains useful data */
2576 AVFormatContext *s = avformat_alloc_context();
2578 AVInputFormat *fmt_in;
2584 /* use feed output format name to find corresponding input format */
2585 fmt_in = av_find_input_format(feed->fmt->name);
2589 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2590 0, NULL, NULL, NULL, NULL);
2594 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2599 /* Now we have the actual streams */
2600 if (s->nb_streams != feed->nb_streams) {
2601 avformat_close_input(&s);
2603 http_log("Feed '%s' stream number does not match registered feed\n",
2604 c->stream->feed_filename);
2608 for (i = 0; i < s->nb_streams; i++) {
2609 AVStream *fst = feed->streams[i];
2610 AVStream *st = s->streams[i];
2611 avcodec_copy_context(fst->codec, st->codec);
2614 avformat_close_input(&s);
2617 c->buffer_ptr = c->buffer;
2622 c->stream->feed_opened = 0;
2624 /* wake up any waiting connections to stop waiting for feed */
2625 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2626 if (c1->state == HTTPSTATE_WAIT_FEED &&
2627 c1->stream->feed == c->stream->feed)
2628 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2633 /********************************************************************/
2636 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2643 str = RTSP_STATUS_CODE2STRING(error_number);
2645 str = "Unknown Error";
2647 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2648 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2650 /* output GMT time */
2653 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2654 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2657 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2659 rtsp_reply_header(c, error_number);
2660 avio_printf(c->pb, "\r\n");
2663 static int rtsp_parse_request(HTTPContext *c)
2665 const char *p, *p1, *p2;
2671 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2673 c->buffer_ptr[0] = '\0';
2676 get_word(cmd, sizeof(cmd), &p);
2677 get_word(url, sizeof(url), &p);
2678 get_word(protocol, sizeof(protocol), &p);
2680 av_strlcpy(c->method, cmd, sizeof(c->method));
2681 av_strlcpy(c->url, url, sizeof(c->url));
2682 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2684 if (avio_open_dyn_buf(&c->pb) < 0) {
2685 /* XXX: cannot do more */
2686 c->pb = NULL; /* safety */
2690 /* check version name */
2691 if (strcmp(protocol, "RTSP/1.0")) {
2692 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2696 /* parse each header line */
2697 /* skip to next line */
2698 while (*p != '\n' && *p != '\0')
2702 while (*p != '\0') {
2703 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2707 if (p2 > p && p2[-1] == '\r')
2709 /* skip empty line */
2713 if (len > sizeof(line) - 1)
2714 len = sizeof(line) - 1;
2715 memcpy(line, p, len);
2717 ff_rtsp_parse_line(header, line, NULL, NULL);
2721 /* handle sequence number */
2722 c->seq = header->seq;
2724 if (!strcmp(cmd, "DESCRIBE"))
2725 rtsp_cmd_describe(c, url);
2726 else if (!strcmp(cmd, "OPTIONS"))
2727 rtsp_cmd_options(c, url);
2728 else if (!strcmp(cmd, "SETUP"))
2729 rtsp_cmd_setup(c, url, header);
2730 else if (!strcmp(cmd, "PLAY"))
2731 rtsp_cmd_play(c, url, header);
2732 else if (!strcmp(cmd, "PAUSE"))
2733 rtsp_cmd_interrupt(c, url, header, 1);
2734 else if (!strcmp(cmd, "TEARDOWN"))
2735 rtsp_cmd_interrupt(c, url, header, 0);
2737 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2740 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2741 c->pb = NULL; /* safety */
2743 /* XXX: cannot do more */
2746 c->buffer_ptr = c->pb_buffer;
2747 c->buffer_end = c->pb_buffer + len;
2748 c->state = RTSPSTATE_SEND_REPLY;
2752 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2753 struct in_addr my_ip)
2755 AVFormatContext *avc;
2756 AVStream *avs = NULL;
2757 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2758 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2763 avc = avformat_alloc_context();
2764 if (!avc || !rtp_format) {
2767 avc->oformat = rtp_format;
2768 av_dict_set(&avc->metadata, "title",
2769 entry ? entry->value : "No Title", 0);
2770 avc->nb_streams = stream->nb_streams;
2771 if (stream->is_multicast) {
2772 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2773 inet_ntoa(stream->multicast_ip),
2774 stream->multicast_port, stream->multicast_ttl);
2776 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2779 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2780 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2782 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2783 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2786 for(i = 0; i < stream->nb_streams; i++) {
2787 avc->streams[i] = &avs[i];
2788 avc->streams[i]->codec = stream->streams[i]->codec;
2790 *pbuffer = av_mallocz(2048);
2791 av_sdp_create(&avc, 1, *pbuffer, 2048);
2794 av_freep(&avc->streams);
2795 av_dict_free(&avc->metadata);
2799 return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2802 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2804 // rtsp_reply_header(c, RTSP_STATUS_OK);
2805 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2806 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2807 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2808 avio_printf(c->pb, "\r\n");
2811 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2813 FFServerStream *stream;
2819 struct sockaddr_in my_addr;
2821 /* find which URL is asked */
2822 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2827 for(stream = config.first_stream; stream; stream = stream->next) {
2828 if (!stream->is_feed &&
2829 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2830 !strcmp(path, stream->filename)) {
2834 /* no stream found */
2835 rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
2839 /* prepare the media description in SDP format */
2841 /* get the host IP */
2842 len = sizeof(my_addr);
2843 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2844 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2845 if (content_length < 0) {
2846 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2849 rtsp_reply_header(c, RTSP_STATUS_OK);
2850 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2851 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2852 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2853 avio_printf(c->pb, "\r\n");
2854 avio_write(c->pb, content, content_length);
2858 static HTTPContext *find_rtp_session(const char *session_id)
2862 if (session_id[0] == '\0')
2865 for(c = first_http_ctx; c; c = c->next) {
2866 if (!strcmp(c->session_id, session_id))
2872 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2874 RTSPTransportField *th;
2877 for(i=0;i<h->nb_transports;i++) {
2878 th = &h->transports[i];
2879 if (th->lower_transport == lower_transport)
2885 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2886 RTSPMessageHeader *h)
2888 FFServerStream *stream;
2889 int stream_index, rtp_port, rtcp_port;
2894 RTSPTransportField *th;
2895 struct sockaddr_in dest_addr;
2896 RTSPActionServerSetup setup;
2898 /* find which URL is asked */
2899 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2904 /* now check each stream */
2905 for(stream = config.first_stream; stream; stream = stream->next) {
2906 if (!stream->is_feed &&
2907 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2908 /* accept aggregate filenames only if single stream */
2909 if (!strcmp(path, stream->filename)) {
2910 if (stream->nb_streams != 1) {
2911 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2918 for(stream_index = 0; stream_index < stream->nb_streams;
2920 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2921 stream->filename, stream_index);
2922 if (!strcmp(path, buf))
2927 /* no stream found */
2928 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2932 /* generate session id if needed */
2933 if (h->session_id[0] == '\0') {
2934 unsigned random0 = av_lfg_get(&random_state);
2935 unsigned random1 = av_lfg_get(&random_state);
2936 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2940 /* find RTP session, and create it if none found */
2941 rtp_c = find_rtp_session(h->session_id);
2943 /* always prefer UDP */
2944 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2946 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2948 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2953 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2954 th->lower_transport);
2956 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2960 /* open input stream */
2961 if (open_input_stream(rtp_c, "") < 0) {
2962 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2967 /* test if stream is OK (test needed because several SETUP needs
2968 to be done for a given file) */
2969 if (rtp_c->stream != stream) {
2970 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2974 /* test if stream is already set up */
2975 if (rtp_c->rtp_ctx[stream_index]) {
2976 rtsp_reply_error(c, RTSP_STATUS_STATE);
2980 /* check transport */
2981 th = find_transport(h, rtp_c->rtp_protocol);
2982 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2983 th->client_port_min <= 0)) {
2984 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2988 /* setup default options */
2989 setup.transport_option[0] = '\0';
2990 dest_addr = rtp_c->from_addr;
2991 dest_addr.sin_port = htons(th->client_port_min);
2994 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2995 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2999 /* now everything is OK, so we can send the connection parameters */
3000 rtsp_reply_header(c, RTSP_STATUS_OK);
3002 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3004 switch(rtp_c->rtp_protocol) {
3005 case RTSP_LOWER_TRANSPORT_UDP:
3006 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3007 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3008 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3009 "client_port=%d-%d;server_port=%d-%d",
3010 th->client_port_min, th->client_port_max,
3011 rtp_port, rtcp_port);
3013 case RTSP_LOWER_TRANSPORT_TCP:
3014 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3015 stream_index * 2, stream_index * 2 + 1);
3020 if (setup.transport_option[0] != '\0')
3021 avio_printf(c->pb, ";%s", setup.transport_option);
3022 avio_printf(c->pb, "\r\n");
3025 avio_printf(c->pb, "\r\n");
3029 /* find an RTP connection by using the session ID. Check consistency
3031 static HTTPContext *find_rtp_session_with_url(const char *url,
3032 const char *session_id)
3040 rtp_c = find_rtp_session(session_id);
3044 /* find which URL is asked */
3045 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3049 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3050 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3051 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3052 rtp_c->stream->filename, s);
3053 if(!strncmp(path, buf, sizeof(buf))) {
3054 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3059 if (len > 0 && path[len - 1] == '/' &&
3060 !strncmp(path, rtp_c->stream->filename, len - 1))
3065 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3069 rtp_c = find_rtp_session_with_url(url, h->session_id);
3071 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3075 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3076 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3077 rtp_c->state != HTTPSTATE_READY) {
3078 rtsp_reply_error(c, RTSP_STATUS_STATE);
3082 rtp_c->state = HTTPSTATE_SEND_DATA;
3084 /* now everything is OK, so we can send the connection parameters */
3085 rtsp_reply_header(c, RTSP_STATUS_OK);
3087 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3088 avio_printf(c->pb, "\r\n");
3091 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3095 rtp_c = find_rtp_session_with_url(url, h->session_id);
3097 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3102 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3103 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3104 rtsp_reply_error(c, RTSP_STATUS_STATE);
3107 rtp_c->state = HTTPSTATE_READY;
3108 rtp_c->first_pts = AV_NOPTS_VALUE;
3111 /* now everything is OK, so we can send the connection parameters */
3112 rtsp_reply_header(c, RTSP_STATUS_OK);
3114 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3115 avio_printf(c->pb, "\r\n");
3118 close_connection(rtp_c);
3121 /********************************************************************/
3124 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3125 FFServerStream *stream, const char *session_id,
3126 enum RTSPLowerTransport rtp_protocol)
3128 HTTPContext *c = NULL;
3129 const char *proto_str;
3131 /* XXX: should output a warning page when coming
3132 close to the connection limit */
3133 if (nb_connections >= config.nb_max_connections)
3136 /* add a new connection */
3137 c = av_mallocz(sizeof(HTTPContext));
3142 c->poll_entry = NULL;
3143 c->from_addr = *from_addr;
3144 c->buffer_size = IOBUFFER_INIT_SIZE;
3145 c->buffer = av_malloc(c->buffer_size);
3150 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3151 c->state = HTTPSTATE_READY;
3152 c->is_packetized = 1;
3153 c->rtp_protocol = rtp_protocol;
3155 /* protocol is shown in statistics */
3156 switch(c->rtp_protocol) {
3157 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3158 proto_str = "MCAST";
3160 case RTSP_LOWER_TRANSPORT_UDP:
3163 case RTSP_LOWER_TRANSPORT_TCP:
3170 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3171 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3173 current_bandwidth += stream->bandwidth;
3175 c->next = first_http_ctx;
3181 av_freep(&c->buffer);
3187 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3188 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3190 static int rtp_new_av_stream(HTTPContext *c,
3191 int stream_index, struct sockaddr_in *dest_addr,
3192 HTTPContext *rtsp_c)
3194 AVFormatContext *ctx;
3197 URLContext *h = NULL;
3199 int max_packet_size;
3201 /* now we can open the relevant output stream */
3202 ctx = avformat_alloc_context();
3205 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3207 st = av_mallocz(sizeof(AVStream));
3210 ctx->nb_streams = 1;
3211 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3214 ctx->streams[0] = st;
3216 if (!c->stream->feed ||
3217 c->stream->feed == c->stream)
3218 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3221 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3223 st->priv_data = NULL;
3225 /* build destination RTP address */
3226 ipaddr = inet_ntoa(dest_addr->sin_addr);
3228 switch(c->rtp_protocol) {
3229 case RTSP_LOWER_TRANSPORT_UDP:
3230 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3233 /* XXX: also pass as parameter to function ? */
3234 if (c->stream->is_multicast) {
3236 ttl = c->stream->multicast_ttl;
3239 snprintf(ctx->filename, sizeof(ctx->filename),
3240 "rtp://%s:%d?multicast=1&ttl=%d",
3241 ipaddr, ntohs(dest_addr->sin_port), ttl);
3243 snprintf(ctx->filename, sizeof(ctx->filename),
3244 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3247 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3249 c->rtp_handles[stream_index] = h;
3250 max_packet_size = h->max_packet_size;
3252 case RTSP_LOWER_TRANSPORT_TCP:
3255 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3261 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3262 ipaddr, ntohs(dest_addr->sin_port),
3263 c->stream->filename, stream_index, c->protocol);
3265 /* normally, no packets should be output here, but the packet size may
3267 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3268 /* XXX: close stream */
3271 if (avformat_write_header(ctx, NULL) < 0) {
3279 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3282 c->rtp_ctx[stream_index] = ctx;
3286 /********************************************************************/
3287 /* ffserver initialization */
3289 static AVStream *add_av_stream1(FFServerStream *stream, AVCodecContext *codec, int copy)
3293 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3296 fst = av_mallocz(sizeof(AVStream));
3300 fst->codec = avcodec_alloc_context3(codec->codec);
3301 avcodec_copy_context(fst->codec, codec);
3303 /* live streams must use the actual feed's codec since it may be
3304 * updated later to carry extradata needed by them.
3308 fst->priv_data = av_mallocz(sizeof(FeedData));
3309 fst->index = stream->nb_streams;
3310 avpriv_set_pts_info(fst, 33, 1, 90000);
3311 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3312 stream->streams[stream->nb_streams++] = fst;
3316 /* return the stream number in the feed */
3317 static int add_av_stream(FFServerStream *feed, AVStream *st)
3320 AVCodecContext *av, *av1;
3324 for(i=0;i<feed->nb_streams;i++) {
3325 av1 = feed->streams[i]->codec;
3326 if (av1->codec_id == av->codec_id &&
3327 av1->codec_type == av->codec_type &&
3328 av1->bit_rate == av->bit_rate) {
3330 switch(av->codec_type) {
3331 case AVMEDIA_TYPE_AUDIO:
3332 if (av1->channels == av->channels &&
3333 av1->sample_rate == av->sample_rate)
3336 case AVMEDIA_TYPE_VIDEO:
3337 if (av1->width == av->width &&
3338 av1->height == av->height &&
3339 av1->time_base.den == av->time_base.den &&
3340 av1->time_base.num == av->time_base.num &&
3341 av1->gop_size == av->gop_size)
3350 fst = add_av_stream1(feed, av, 0);
3353 if (av_stream_get_recommended_encoder_configuration(st))
3354 av_stream_set_recommended_encoder_configuration(fst,
3355 av_strdup(av_stream_get_recommended_encoder_configuration(st)));
3356 return feed->nb_streams - 1;
3359 static void remove_stream(FFServerStream *stream)
3361 FFServerStream **ps;
3362 ps = &config.first_stream;
3371 /* specific MPEG4 handling : we extract the raw parameters */
3372 static void extract_mpeg4_header(AVFormatContext *infile)
3374 int mpeg4_count, i, size;
3379 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3382 for(i=0;i<infile->nb_streams;i++) {
3383 st = infile->streams[i];
3384 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3385 st->codec->extradata_size == 0) {
3392 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3393 while (mpeg4_count > 0) {
3394 if (av_read_frame(infile, &pkt) < 0)
3396 st = infile->streams[pkt.stream_index];
3397 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3398 st->codec->extradata_size == 0) {
3399 av_freep(&st->codec->extradata);
3400 /* fill extradata with the header */
3401 /* XXX: we make hard suppositions here ! */
3403 while (p < pkt.data + pkt.size - 4) {
3404 /* stop when vop header is found */
3405 if (p[0] == 0x00 && p[1] == 0x00 &&
3406 p[2] == 0x01 && p[3] == 0xb6) {
3407 size = p - pkt.data;
3408 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3409 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3410 st->codec->extradata_size = size;
3411 memcpy(st->codec->extradata, pkt.data, size);
3418 av_free_packet(&pkt);
3422 /* compute the needed AVStream for each file */
3423 static void build_file_streams(void)
3425 FFServerStream *stream, *stream_next;
3428 /* gather all streams */
3429 for(stream = config.first_stream; stream; stream = stream_next) {
3430 AVFormatContext *infile = NULL;
3431 stream_next = stream->next;
3432 if (stream->stream_type == STREAM_TYPE_LIVE &&
3434 /* the stream comes from a file */
3435 /* try to open the file */
3437 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3438 /* specific case : if transport stream output to RTP,
3439 we use a raw transport stream reader */
3440 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3443 if (!stream->feed_filename[0]) {
3444 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3448 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3449 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3450 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3451 /* remove stream (no need to spend more time on it) */
3453 remove_stream(stream);
3455 /* find all the AVStreams inside and reference them in
3457 if (avformat_find_stream_info(infile, NULL) < 0) {
3458 http_log("Could not find codec parameters from '%s'\n",
3459 stream->feed_filename);
3460 avformat_close_input(&infile);
3463 extract_mpeg4_header(infile);
3465 for(i=0;i<infile->nb_streams;i++)
3466 add_av_stream1(stream, infile->streams[i]->codec, 1);
3468 avformat_close_input(&infile);
3474 /* compute the needed AVStream for each feed */
3475 static void build_feed_streams(void)
3477 FFServerStream *stream, *feed;
3480 /* gather all streams */
3481 for(stream = config.first_stream; stream; stream = stream->next) {
3482 feed = stream->feed;
3484 if (stream->is_feed) {
3485 for(i=0;i<stream->nb_streams;i++)
3486 stream->feed_streams[i] = i;
3488 /* we handle a stream coming from a feed */
3489 for(i=0;i<stream->nb_streams;i++)
3490 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3495 /* create feed files if needed */
3496 for(feed = config.first_feed; feed; feed = feed->next_feed) {
3499 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3500 /* See if it matches */
3501 AVFormatContext *s = NULL;
3504 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3505 /* set buffer size */
3506 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3507 /* Now see if it matches */
3508 if (s->nb_streams == feed->nb_streams) {
3510 for(i=0;i<s->nb_streams;i++) {
3512 sf = feed->streams[i];
3515 if (sf->index != ss->index ||
3517 http_log("Index & Id do not match for stream %d (%s)\n",
3518 i, feed->feed_filename);
3521 AVCodecContext *ccf, *ccs;
3525 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3527 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3528 http_log("Codecs do not match for stream %d\n", i);
3530 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3531 http_log("Codec bitrates do not match for stream %d\n", i);
3533 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3534 if (CHECK_CODEC(time_base.den) ||
3535 CHECK_CODEC(time_base.num) ||
3536 CHECK_CODEC(width) ||
3537 CHECK_CODEC(height)) {
3538 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3541 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3542 if (CHECK_CODEC(sample_rate) ||
3543 CHECK_CODEC(channels) ||
3544 CHECK_CODEC(frame_size)) {
3545 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3549 http_log("Unknown codec type\n");
3557 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3558 feed->feed_filename, s->nb_streams, feed->nb_streams);
3560 avformat_close_input(&s);
3562 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3563 feed->feed_filename);
3566 if (feed->readonly) {
3567 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3568 feed->feed_filename);
3571 unlink(feed->feed_filename);
3574 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3575 AVFormatContext *s = avformat_alloc_context();
3577 if (feed->readonly) {
3578 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3579 feed->feed_filename);
3583 /* only write the header of the ffm file */
3584 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3585 http_log("Could not open output feed file '%s'\n",
3586 feed->feed_filename);
3589 s->oformat = feed->fmt;
3590 s->nb_streams = feed->nb_streams;
3591 s->streams = feed->streams;
3592 if (avformat_write_header(s, NULL) < 0) {
3593 http_log("Container doesn't support the required parameters\n");
3596 /* XXX: need better API */
3597 av_freep(&s->priv_data);
3601 avformat_free_context(s);
3603 /* get feed size and write index */
3604 fd = open(feed->feed_filename, O_RDONLY);
3606 http_log("Could not open output feed file '%s'\n",
3607 feed->feed_filename);
3611 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3612 feed->feed_size = lseek(fd, 0, SEEK_END);
3613 /* ensure that we do not wrap before the end of file */
3614 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3615 feed->feed_max_size = feed->feed_size;
3621 /* compute the bandwidth used by each stream */
3622 static void compute_bandwidth(void)
3626 FFServerStream *stream;
3628 for(stream = config.first_stream; stream; stream = stream->next) {
3630 for(i=0;i<stream->nb_streams;i++) {
3631 AVStream *st = stream->streams[i];
3632 switch(st->codec->codec_type) {
3633 case AVMEDIA_TYPE_AUDIO:
3634 case AVMEDIA_TYPE_VIDEO:
3635 bandwidth += st->codec->bit_rate;
3641 stream->bandwidth = (bandwidth + 999) / 1000;
3645 static void handle_child_exit(int sig)
3650 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3651 FFServerStream *feed;
3653 for (feed = config.first_feed; feed; feed = feed->next) {
3654 if (feed->pid == pid) {
3655 int uptime = time(0) - feed->pid_start;
3658 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
3661 /* Turn off any more restarts */
3662 ffserver_free_child_args(&feed->child_argv);
3667 need_to_start_children = 1;
3670 static void opt_debug(void)
3673 snprintf(config.logfilename, sizeof(config.logfilename), "-");
3676 void show_help_default(const char *opt, const char *arg)
3678 printf("usage: ffserver [options]\n"
3679 "Hyper fast multi format Audio/Video streaming server\n");
3681 show_help_options(options, "Main options:", 0, 0, 0);
3684 static const OptionDef options[] = {
3685 #include "cmdutils_common_opts.h"
3686 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3687 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3688 { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3692 int main(int argc, char **argv)
3694 struct sigaction sigact = { { 0 } };
3697 config.filename = av_strdup("/etc/ffserver.conf");
3699 parse_loglevel(argc, argv, options);
3701 avformat_network_init();
3703 show_banner(argc, argv, options);
3705 my_program_name = argv[0];
3707 parse_options(NULL, argc, argv, options, NULL);
3709 unsetenv("http_proxy"); /* Kill the http_proxy */
3711 av_lfg_init(&random_state, av_get_random_seed());
3713 sigact.sa_handler = handle_child_exit;
3714 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3715 sigaction(SIGCHLD, &sigact, 0);
3717 if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3718 fprintf(stderr, "Error reading configuration file '%s': %s\n",
3719 config.filename, av_err2str(ret));
3722 av_freep(&config.filename);
3724 /* open log file if needed */
3725 if (config.logfilename[0] != '\0') {
3726 if (!strcmp(config.logfilename, "-"))
3729 logfile = fopen(config.logfilename, "a");
3730 av_log_set_callback(http_av_log);
3733 build_file_streams();
3735 build_feed_streams();
3737 compute_bandwidth();
3740 signal(SIGPIPE, SIG_IGN);
3742 if (http_server() < 0) {
3743 http_log("Could not start server\n");