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,
224 RTSPMessageHeader *h);
225 static void rtsp_cmd_play(HTTPContext *c, const char *url,
226 RTSPMessageHeader *h);
227 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url,
228 RTSPMessageHeader *h, int pause_only);
231 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
232 struct in_addr my_ip);
235 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
236 FFServerStream *stream,
237 const char *session_id,
238 enum RTSPLowerTransport rtp_protocol);
239 static int rtp_new_av_stream(HTTPContext *c,
240 int stream_index, struct sockaddr_in *dest_addr,
241 HTTPContext *rtsp_c);
243 static const char *my_program_name;
245 static int no_launch;
246 static int need_to_start_children;
248 /* maximum number of simultaneous HTTP connections */
249 static unsigned int nb_connections;
251 static uint64_t current_bandwidth;
253 static int64_t cur_time; // Making this global saves on passing it around everywhere
255 static AVLFG random_state;
257 static FILE *logfile = NULL;
259 static void htmlstrip(char *s) {
261 s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
267 static int64_t ffm_read_write_index(int fd)
271 if (lseek(fd, 8, SEEK_SET) < 0)
273 if (read(fd, buf, 8) != 8)
278 static int ffm_write_write_index(int fd, int64_t pos)
284 buf[i] = (pos >> (56 - i * 8)) & 0xff;
285 if (lseek(fd, 8, SEEK_SET) < 0)
287 if (write(fd, buf, 8) != 8)
292 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
295 FFMContext *ffm = s->priv_data;
296 ffm->write_index = pos;
297 ffm->file_size = file_size;
300 static char *ctime1(char *buf2, int buf_size)
307 av_strlcpy(buf2, p, buf_size);
308 p = buf2 + strlen(p) - 1;
314 static void http_vlog(const char *fmt, va_list vargs)
316 static int print_prefix = 1;
320 ctime1(buf, sizeof(buf));
321 fprintf(logfile, "%s ", buf);
323 print_prefix = strstr(fmt, "\n") != NULL;
324 vfprintf(logfile, fmt, vargs);
330 __attribute__ ((format (printf, 1, 2)))
332 static void http_log(const char *fmt, ...)
335 va_start(vargs, fmt);
336 http_vlog(fmt, vargs);
340 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
342 static int print_prefix = 1;
343 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
344 if (level > av_log_get_level())
346 if (print_prefix && avc)
347 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
348 print_prefix = strstr(fmt, "\n") != NULL;
349 http_vlog(fmt, vargs);
352 static void log_connection(HTTPContext *c)
357 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
358 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
359 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
362 static void update_datarate(DataRateData *drd, int64_t count)
364 if (!drd->time1 && !drd->count1) {
365 drd->time1 = drd->time2 = cur_time;
366 drd->count1 = drd->count2 = count;
367 } else if (cur_time - drd->time2 > 5000) {
368 drd->time1 = drd->time2;
369 drd->count1 = drd->count2;
370 drd->time2 = cur_time;
375 /* In bytes per second */
376 static int compute_datarate(DataRateData *drd, int64_t count)
378 if (cur_time == drd->time1)
381 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
385 static void start_children(FFServerStream *feed)
394 /* replace "ffserver" with "ffmpeg" in the path of current
395 * program. Ignore user provided path */
396 av_strlcpy(pathname, my_program_name, sizeof(pathname));
398 slash = strrchr(pathname, '/');
403 strcpy(slash, "ffmpeg");
405 for (; feed; feed = feed->next) {
407 if (!feed->child_argv || feed->pid)
410 feed->pid_start = time(0);
414 http_log("Unable to create children\n");
423 http_log("Launch command line: ");
424 http_log("%s ", pathname);
426 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
427 http_log("%s ", feed->child_argv[i]);
430 for (i = 3; i < 256; i++)
434 if (!freopen("/dev/null", "r", stdin))
435 http_log("failed to redirect STDIN to /dev/null\n;");
436 if (!freopen("/dev/null", "w", stdout))
437 http_log("failed to redirect STDOUT to /dev/null\n;");
438 if (!freopen("/dev/null", "w", stderr))
439 http_log("failed to redirect STDERR to /dev/null\n;");
442 signal(SIGPIPE, SIG_DFL);
443 execvp(pathname, feed->child_argv);
448 /* open a listening socket */
449 static int socket_open_listen(struct sockaddr_in *my_addr)
453 server_fd = socket(AF_INET,SOCK_STREAM,0);
460 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)))
461 av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n");
463 my_addr->sin_family = AF_INET;
464 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
466 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
468 closesocket(server_fd);
472 if (listen (server_fd, 5) < 0) {
474 closesocket(server_fd);
478 if (ff_socket_nonblock(server_fd, 1) < 0)
479 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
484 /* start all multicast streams */
485 static void start_multicast(void)
487 FFServerStream *stream;
490 struct sockaddr_in dest_addr = {0};
491 int default_port, stream_index;
492 unsigned int random0, random1;
495 for(stream = config.first_stream; stream; stream = stream->next) {
496 if (!stream->is_multicast)
498 random0 = av_lfg_get(&random_state);
499 random1 = av_lfg_get(&random_state);
500 /* open the RTP connection */
501 snprintf(session_id, sizeof(session_id), "%08x%08x",
504 /* choose a port if none given */
505 if (stream->multicast_port == 0) {
506 stream->multicast_port = default_port;
510 dest_addr.sin_family = AF_INET;
511 dest_addr.sin_addr = stream->multicast_ip;
512 dest_addr.sin_port = htons(stream->multicast_port);
514 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
515 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
519 if (open_input_stream(rtp_c, "") < 0) {
520 http_log("Could not open input stream for stream '%s'\n",
525 /* open each RTP stream */
526 for(stream_index = 0; stream_index < stream->nb_streams;
528 dest_addr.sin_port = htons(stream->multicast_port +
530 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL)
534 http_log("Could not open output stream '%s/streamid=%d'\n",
535 stream->filename, stream_index);
539 rtp_c->state = HTTPSTATE_SEND_DATA;
543 /* main loop of the HTTP server */
544 static int http_server(void)
546 int server_fd = 0, rtsp_server_fd = 0;
548 struct pollfd *poll_table, *poll_entry;
549 HTTPContext *c, *c_next;
551 if(!(poll_table = av_mallocz_array(config.nb_max_http_connections + 2, sizeof(*poll_table)))) {
552 http_log("Impossible to allocate a poll table handling %d connections.\n", config.nb_max_http_connections);
556 if (config.http_addr.sin_port) {
557 server_fd = socket_open_listen(&config.http_addr);
564 if (config.rtsp_addr.sin_port) {
565 rtsp_server_fd = socket_open_listen(&config.rtsp_addr);
566 if (rtsp_server_fd < 0) {
568 closesocket(server_fd);
573 if (!rtsp_server_fd && !server_fd) {
574 http_log("HTTP and RTSP disabled.\n");
579 http_log("FFserver started.\n");
581 start_children(config.first_feed);
586 poll_entry = poll_table;
588 poll_entry->fd = server_fd;
589 poll_entry->events = POLLIN;
592 if (rtsp_server_fd) {
593 poll_entry->fd = rtsp_server_fd;
594 poll_entry->events = POLLIN;
598 /* wait for events on each HTTP handle */
605 case HTTPSTATE_SEND_HEADER:
606 case RTSPSTATE_SEND_REPLY:
607 case RTSPSTATE_SEND_PACKET:
608 c->poll_entry = poll_entry;
610 poll_entry->events = POLLOUT;
613 case HTTPSTATE_SEND_DATA_HEADER:
614 case HTTPSTATE_SEND_DATA:
615 case HTTPSTATE_SEND_DATA_TRAILER:
616 if (!c->is_packetized) {
617 /* for TCP, we output as much as we can
618 * (may need to put a limit) */
619 c->poll_entry = poll_entry;
621 poll_entry->events = POLLOUT;
624 /* when ffserver is doing the timing, we work by
625 looking at which packet needs to be sent every
627 /* one tick wait XXX: 10 ms assumed */
632 case HTTPSTATE_WAIT_REQUEST:
633 case HTTPSTATE_RECEIVE_DATA:
634 case HTTPSTATE_WAIT_FEED:
635 case RTSPSTATE_WAIT_REQUEST:
636 /* need to catch errors */
637 c->poll_entry = poll_entry;
639 poll_entry->events = POLLIN;/* Maybe this will work */
643 c->poll_entry = NULL;
649 /* wait for an event on one connection. We poll at least every
650 second to handle timeouts */
652 ret = poll(poll_table, poll_entry - poll_table, delay);
653 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
654 ff_neterrno() != AVERROR(EINTR)) {
660 cur_time = av_gettime() / 1000;
662 if (need_to_start_children) {
663 need_to_start_children = 0;
664 start_children(config.first_feed);
667 /* now handle the events */
668 for(c = first_http_ctx; c; c = c_next) {
670 if (handle_connection(c) < 0) {
672 /* close and free the connection */
677 poll_entry = poll_table;
679 /* new HTTP connection request ? */
680 if (poll_entry->revents & POLLIN)
681 new_connection(server_fd, 0);
684 if (rtsp_server_fd) {
685 /* new RTSP connection request ? */
686 if (poll_entry->revents & POLLIN)
687 new_connection(rtsp_server_fd, 1);
692 /* start waiting for a new HTTP/RTSP request */
693 static void start_wait_request(HTTPContext *c, int is_rtsp)
695 c->buffer_ptr = c->buffer;
696 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
699 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
700 c->state = RTSPSTATE_WAIT_REQUEST;
702 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
703 c->state = HTTPSTATE_WAIT_REQUEST;
707 static void http_send_too_busy_reply(int fd)
710 int len = snprintf(buffer, sizeof(buffer),
711 "HTTP/1.0 503 Server too busy\r\n"
712 "Content-type: text/html\r\n"
714 "<html><head><title>Too busy</title></head><body>\r\n"
715 "<p>The server is too busy to serve your request at this time.</p>\r\n"
716 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
717 "</body></html>\r\n",
718 nb_connections, config.nb_max_connections);
719 av_assert0(len < sizeof(buffer));
720 if (send(fd, buffer, len, 0) < len)
721 av_log(NULL, AV_LOG_WARNING, "Could not send too-busy reply, send() failed\n");
725 static void new_connection(int server_fd, int is_rtsp)
727 struct sockaddr_in from_addr;
730 HTTPContext *c = NULL;
732 len = sizeof(from_addr);
733 fd = accept(server_fd, (struct sockaddr *)&from_addr,
736 http_log("error during accept %s\n", strerror(errno));
739 if (ff_socket_nonblock(fd, 1) < 0)
740 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
742 if (nb_connections >= config.nb_max_connections) {
743 http_send_too_busy_reply(fd);
747 /* add a new connection */
748 c = av_mallocz(sizeof(HTTPContext));
753 c->poll_entry = NULL;
754 c->from_addr = from_addr;
755 c->buffer_size = IOBUFFER_INIT_SIZE;
756 c->buffer = av_malloc(c->buffer_size);
760 c->next = first_http_ctx;
764 start_wait_request(c, is_rtsp);
770 av_freep(&c->buffer);
776 static void close_connection(HTTPContext *c)
778 HTTPContext **cp, *c1;
780 AVFormatContext *ctx;
784 /* remove connection from list */
785 cp = &first_http_ctx;
794 /* remove references, if any (XXX: do it faster) */
795 for(c1 = first_http_ctx; c1; c1 = c1->next) {
800 /* remove connection associated resources */
804 /* close each frame parser */
805 for(i=0;i<c->fmt_in->nb_streams;i++) {
806 st = c->fmt_in->streams[i];
807 if (st->codec->codec)
808 avcodec_close(st->codec);
810 avformat_close_input(&c->fmt_in);
813 /* free RTP output streams if any */
816 nb_streams = c->stream->nb_streams;
818 for(i=0;i<nb_streams;i++) {
821 av_write_trailer(ctx);
822 av_dict_free(&ctx->metadata);
823 av_freep(&ctx->streams[0]);
826 h = c->rtp_handles[i];
833 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
836 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
837 av_write_trailer(ctx);
838 av_freep(&c->pb_buffer);
839 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
844 for(i=0; i<ctx->nb_streams; i++)
845 av_freep(&ctx->streams[i]);
846 av_freep(&ctx->streams);
847 av_freep(&ctx->priv_data);
849 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
850 current_bandwidth -= c->stream->bandwidth;
852 /* signal that there is no feed if we are the feeder socket */
853 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
854 c->stream->feed_opened = 0;
858 av_freep(&c->pb_buffer);
859 av_freep(&c->packet_buffer);
860 av_freep(&c->buffer);
865 static int handle_connection(HTTPContext *c)
870 case HTTPSTATE_WAIT_REQUEST:
871 case RTSPSTATE_WAIT_REQUEST:
873 if ((c->timeout - cur_time) < 0)
875 if (c->poll_entry->revents & (POLLERR | POLLHUP))
878 /* no need to read if no events */
879 if (!(c->poll_entry->revents & POLLIN))
883 len = recv(c->fd, c->buffer_ptr, 1, 0);
885 if (ff_neterrno() != AVERROR(EAGAIN) &&
886 ff_neterrno() != AVERROR(EINTR))
888 } else if (len == 0) {
891 /* search for end of request. */
893 c->buffer_ptr += len;
895 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
896 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
897 /* request found : parse it and reply */
898 if (c->state == HTTPSTATE_WAIT_REQUEST) {
899 ret = http_parse_request(c);
901 ret = rtsp_parse_request(c);
905 } else if (ptr >= c->buffer_end) {
906 /* request too long: cannot do anything */
908 } else goto read_loop;
912 case HTTPSTATE_SEND_HEADER:
913 if (c->poll_entry->revents & (POLLERR | POLLHUP))
916 /* no need to write if no events */
917 if (!(c->poll_entry->revents & POLLOUT))
919 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
921 if (ff_neterrno() != AVERROR(EAGAIN) &&
922 ff_neterrno() != AVERROR(EINTR)) {
923 goto close_connection;
926 c->buffer_ptr += len;
928 c->stream->bytes_served += len;
929 c->data_count += len;
930 if (c->buffer_ptr >= c->buffer_end) {
931 av_freep(&c->pb_buffer);
935 /* all the buffer was sent : synchronize to the incoming
937 c->state = HTTPSTATE_SEND_DATA_HEADER;
938 c->buffer_ptr = c->buffer_end = c->buffer;
943 case HTTPSTATE_SEND_DATA:
944 case HTTPSTATE_SEND_DATA_HEADER:
945 case HTTPSTATE_SEND_DATA_TRAILER:
946 /* for packetized output, we consider we can always write (the
947 input streams set the speed). It may be better to verify
948 that we do not rely too much on the kernel queues */
949 if (!c->is_packetized) {
950 if (c->poll_entry->revents & (POLLERR | POLLHUP))
953 /* no need to read if no events */
954 if (!(c->poll_entry->revents & POLLOUT))
957 if (http_send_data(c) < 0)
959 /* close connection if trailer sent */
960 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
963 case HTTPSTATE_RECEIVE_DATA:
964 /* no need to read if no events */
965 if (c->poll_entry->revents & (POLLERR | POLLHUP))
967 if (!(c->poll_entry->revents & POLLIN))
969 if (http_receive_data(c) < 0)
972 case HTTPSTATE_WAIT_FEED:
973 /* no need to read if no events */
974 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
977 /* nothing to do, we'll be waken up by incoming feed packets */
980 case RTSPSTATE_SEND_REPLY:
981 if (c->poll_entry->revents & (POLLERR | POLLHUP))
982 goto close_connection;
983 /* no need to write if no events */
984 if (!(c->poll_entry->revents & POLLOUT))
986 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
988 if (ff_neterrno() != AVERROR(EAGAIN) &&
989 ff_neterrno() != AVERROR(EINTR)) {
990 goto close_connection;
993 c->buffer_ptr += len;
994 c->data_count += len;
995 if (c->buffer_ptr >= c->buffer_end) {
996 /* all the buffer was sent : wait for a new request */
997 av_freep(&c->pb_buffer);
998 start_wait_request(c, 1);
1002 case RTSPSTATE_SEND_PACKET:
1003 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1004 av_freep(&c->packet_buffer);
1007 /* no need to write if no events */
1008 if (!(c->poll_entry->revents & POLLOUT))
1010 len = send(c->fd, c->packet_buffer_ptr,
1011 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1013 if (ff_neterrno() != AVERROR(EAGAIN) &&
1014 ff_neterrno() != AVERROR(EINTR)) {
1015 /* error : close connection */
1016 av_freep(&c->packet_buffer);
1020 c->packet_buffer_ptr += len;
1021 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1022 /* all the buffer was sent : wait for a new request */
1023 av_freep(&c->packet_buffer);
1024 c->state = RTSPSTATE_WAIT_REQUEST;
1028 case HTTPSTATE_READY:
1037 av_freep(&c->pb_buffer);
1041 static int extract_rates(char *rates, int ratelen, const char *request)
1045 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1046 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1047 const char *q = p + 7;
1049 while (*q && *q != '\n' && av_isspace(*q))
1052 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1058 memset(rates, 0xff, ratelen);
1061 while (*q && *q != '\n' && *q != ':')
1064 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1068 if (stream_no < ratelen && stream_no >= 0)
1069 rates[stream_no] = rate_no;
1071 while (*q && *q != '\n' && !av_isspace(*q))
1078 p = strchr(p, '\n');
1088 static int find_stream_in_feed(FFServerStream *feed, AVCodecContext *codec, int bit_rate)
1091 int best_bitrate = 100000000;
1094 for (i = 0; i < feed->nb_streams; i++) {
1095 AVCodecContext *feed_codec = feed->streams[i]->codec;
1097 if (feed_codec->codec_id != codec->codec_id ||
1098 feed_codec->sample_rate != codec->sample_rate ||
1099 feed_codec->width != codec->width ||
1100 feed_codec->height != codec->height)
1103 /* Potential stream */
1105 /* We want the fastest stream less than bit_rate, or the slowest
1106 * faster than bit_rate
1109 if (feed_codec->bit_rate <= bit_rate) {
1110 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1111 best_bitrate = feed_codec->bit_rate;
1115 if (feed_codec->bit_rate < best_bitrate) {
1116 best_bitrate = feed_codec->bit_rate;
1125 static int modify_current_stream(HTTPContext *c, char *rates)
1128 FFServerStream *req = c->stream;
1129 int action_required = 0;
1131 /* Not much we can do for a feed */
1135 for (i = 0; i < req->nb_streams; i++) {
1136 AVCodecContext *codec = req->streams[i]->codec;
1140 c->switch_feed_streams[i] = req->feed_streams[i];
1143 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1146 /* Wants off or slow */
1147 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1149 /* This doesn't work well when it turns off the only stream! */
1150 c->switch_feed_streams[i] = -2;
1151 c->feed_streams[i] = -2;
1156 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1157 action_required = 1;
1160 return action_required;
1163 static void get_word(char *buf, int buf_size, const char **pp)
1169 p += strspn(p, SPACE_CHARS);
1171 while (!av_isspace(*p) && *p != '\0') {
1172 if ((q - buf) < buf_size - 1)
1181 static FFServerIPAddressACL* parse_dynamic_acl(FFServerStream *stream, HTTPContext *c)
1186 FFServerIPAddressACL *acl = NULL;
1190 f = fopen(stream->dynamic_acl, "r");
1192 perror(stream->dynamic_acl);
1196 acl = av_mallocz(sizeof(FFServerIPAddressACL));
1200 if (fgets(line, sizeof(line), f) == NULL)
1204 while (av_isspace(*p))
1206 if (*p == '\0' || *p == '#')
1208 ffserver_get_arg(cmd, sizeof(cmd), &p);
1210 if (!av_strcasecmp(cmd, "ACL"))
1211 ffserver_parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1218 static void free_acl_list(FFServerIPAddressACL *in_acl)
1220 FFServerIPAddressACL *pacl, *pacl2;
1230 static int validate_acl_list(FFServerIPAddressACL *in_acl, HTTPContext *c)
1232 enum FFServerIPAddressAction last_action = IP_DENY;
1233 FFServerIPAddressACL *acl;
1234 struct in_addr *src = &c->from_addr.sin_addr;
1235 unsigned long src_addr = src->s_addr;
1237 for (acl = in_acl; acl; acl = acl->next) {
1238 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1239 return (acl->action == IP_ALLOW) ? 1 : 0;
1240 last_action = acl->action;
1243 /* Nothing matched, so return not the last action */
1244 return (last_action == IP_DENY) ? 1 : 0;
1247 static int validate_acl(FFServerStream *stream, HTTPContext *c)
1250 FFServerIPAddressACL *acl;
1252 /* if stream->acl is null validate_acl_list will return 1 */
1253 ret = validate_acl_list(stream->acl, c);
1255 if (stream->dynamic_acl[0]) {
1256 acl = parse_dynamic_acl(stream, c);
1258 ret = validate_acl_list(acl, c);
1266 /* compute the real filename of a file by matching it without its
1267 extensions to all the stream's filenames */
1268 static void compute_real_filename(char *filename, int max_size)
1273 FFServerStream *stream;
1275 /* compute filename by matching without the file extensions */
1276 av_strlcpy(file1, filename, sizeof(file1));
1277 p = strrchr(file1, '.');
1280 for(stream = config.first_stream; stream; stream = stream->next) {
1281 av_strlcpy(file2, stream->filename, sizeof(file2));
1282 p = strrchr(file2, '.');
1285 if (!strcmp(file1, file2)) {
1286 av_strlcpy(filename, stream->filename, max_size);
1301 /* parse HTTP request and prepare header */
1302 static int http_parse_request(HTTPContext *c)
1306 enum RedirType redir_type;
1308 char info[1024], filename[1024];
1312 const char *mime_type;
1313 FFServerStream *stream;
1316 const char *useragent = 0;
1319 get_word(cmd, sizeof(cmd), &p);
1320 av_strlcpy(c->method, cmd, sizeof(c->method));
1322 if (!strcmp(cmd, "GET"))
1324 else if (!strcmp(cmd, "POST"))
1329 get_word(url, sizeof(url), &p);
1330 av_strlcpy(c->url, url, sizeof(c->url));
1332 get_word(protocol, sizeof(protocol), (const char **)&p);
1333 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1336 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1339 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1341 /* find the filename and the optional info string in the request */
1342 p1 = strchr(url, '?');
1344 av_strlcpy(info, p1, sizeof(info));
1349 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1351 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1352 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1354 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1358 p = strchr(p, '\n');
1365 redir_type = REDIR_NONE;
1366 if (av_match_ext(filename, "asx")) {
1367 redir_type = REDIR_ASX;
1368 filename[strlen(filename)-1] = 'f';
1369 } else if (av_match_ext(filename, "asf") &&
1370 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8))) {
1371 /* if this isn't WMP or lookalike, return the redirector file */
1372 redir_type = REDIR_ASF;
1373 } else if (av_match_ext(filename, "rpm,ram")) {
1374 redir_type = REDIR_RAM;
1375 strcpy(filename + strlen(filename)-2, "m");
1376 } else if (av_match_ext(filename, "rtsp")) {
1377 redir_type = REDIR_RTSP;
1378 compute_real_filename(filename, sizeof(filename) - 1);
1379 } else if (av_match_ext(filename, "sdp")) {
1380 redir_type = REDIR_SDP;
1381 compute_real_filename(filename, sizeof(filename) - 1);
1384 // "redirect" / request to index.html
1385 if (!strlen(filename))
1386 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1388 stream = config.first_stream;
1390 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1392 stream = stream->next;
1395 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1396 http_log("File '%s' not found\n", url);
1401 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1402 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1404 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1405 c->http_error = 301;
1407 snprintf(q, c->buffer_size,
1408 "HTTP/1.0 301 Moved\r\n"
1410 "Content-type: text/html\r\n"
1412 "<html><head><title>Moved</title></head><body>\r\n"
1413 "You should be <a href=\"%s\">redirected</a>.\r\n"
1414 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1416 /* prepare output buffer */
1417 c->buffer_ptr = c->buffer;
1419 c->state = HTTPSTATE_SEND_HEADER;
1423 /* If this is WMP, get the rate information */
1424 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1425 if (modify_current_stream(c, ratebuf)) {
1426 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1427 if (c->switch_feed_streams[i] >= 0)
1428 c->switch_feed_streams[i] = -1;
1433 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1434 current_bandwidth += stream->bandwidth;
1436 /* If already streaming this feed, do not let start another feeder. */
1437 if (stream->feed_opened) {
1438 snprintf(msg, sizeof(msg), "This feed is already being received.");
1439 http_log("Feed '%s' already being received\n", stream->feed_filename);
1443 if (c->post == 0 && config.max_bandwidth < current_bandwidth) {
1444 c->http_error = 503;
1446 snprintf(q, c->buffer_size,
1447 "HTTP/1.0 503 Server too busy\r\n"
1448 "Content-type: text/html\r\n"
1450 "<html><head><title>Too busy</title></head><body>\r\n"
1451 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1452 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1453 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1454 "</body></html>\r\n", current_bandwidth, config.max_bandwidth);
1456 /* prepare output buffer */
1457 c->buffer_ptr = c->buffer;
1459 c->state = HTTPSTATE_SEND_HEADER;
1463 if (redir_type != REDIR_NONE) {
1464 const char *hostinfo = 0;
1466 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1467 if (av_strncasecmp(p, "Host:", 5) == 0) {
1471 p = strchr(p, '\n');
1482 while (av_isspace(*hostinfo))
1485 eoh = strchr(hostinfo, '\n');
1487 if (eoh[-1] == '\r')
1490 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1491 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1492 hostbuf[eoh - hostinfo] = 0;
1494 c->http_error = 200;
1496 switch(redir_type) {
1498 snprintf(q, c->buffer_size,
1499 "HTTP/1.0 200 ASX Follows\r\n"
1500 "Content-type: video/x-ms-asf\r\n"
1502 "<ASX Version=\"3\">\r\n"
1503 //"<!-- Autogenerated by ffserver -->\r\n"
1504 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1505 "</ASX>\r\n", hostbuf, filename, info);
1509 snprintf(q, c->buffer_size,
1510 "HTTP/1.0 200 RAM Follows\r\n"
1511 "Content-type: audio/x-pn-realaudio\r\n"
1513 "# Autogenerated by ffserver\r\n"
1514 "http://%s/%s%s\r\n", hostbuf, filename, info);
1518 snprintf(q, c->buffer_size,
1519 "HTTP/1.0 200 ASF Redirect follows\r\n"
1520 "Content-type: video/x-ms-asf\r\n"
1523 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1528 char hostname[256], *p;
1529 /* extract only hostname */
1530 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1531 p = strrchr(hostname, ':');
1534 snprintf(q, c->buffer_size,
1535 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1536 /* XXX: incorrect MIME type ? */
1537 "Content-type: application/x-rtsp\r\n"
1539 "rtsp://%s:%d/%s\r\n", hostname, ntohs(config.rtsp_addr.sin_port), filename);
1548 struct sockaddr_in my_addr;
1550 snprintf(q, c->buffer_size,
1551 "HTTP/1.0 200 OK\r\n"
1552 "Content-type: application/sdp\r\n"
1556 len = sizeof(my_addr);
1558 /* XXX: Should probably fail? */
1559 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1560 http_log("getsockname() failed\n");
1562 /* XXX: should use a dynamic buffer */
1563 sdp_data_size = prepare_sdp_description(stream,
1566 if (sdp_data_size > 0) {
1567 memcpy(q, sdp_data, sdp_data_size);
1579 /* prepare output buffer */
1580 c->buffer_ptr = c->buffer;
1582 c->state = HTTPSTATE_SEND_HEADER;
1588 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1592 stream->conns_served++;
1594 /* XXX: add there authenticate and IP match */
1597 /* if post, it means a feed is being sent */
1598 if (!stream->is_feed) {
1599 /* However it might be a status report from WMP! Let us log the
1600 * data as it might come handy one day. */
1601 const char *logline = 0;
1604 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1605 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1609 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1610 client_id = strtol(p + 18, 0, 10);
1611 p = strchr(p, '\n');
1619 char *eol = strchr(logline, '\n');
1624 if (eol[-1] == '\r')
1626 http_log("%.*s\n", (int) (eol - logline), logline);
1627 c->suppress_log = 1;
1632 http_log("\nGot request:\n%s\n", c->buffer);
1635 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1638 /* Now we have to find the client_id */
1639 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1640 if (wmpc->wmp_client_id == client_id)
1644 if (wmpc && modify_current_stream(wmpc, ratebuf))
1645 wmpc->switch_pending = 1;
1648 snprintf(msg, sizeof(msg), "POST command not handled");
1652 if (http_start_receive_data(c) < 0) {
1653 snprintf(msg, sizeof(msg), "could not open feed");
1657 c->state = HTTPSTATE_RECEIVE_DATA;
1662 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1663 http_log("\nGot request:\n%s\n", c->buffer);
1666 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1669 /* open input stream */
1670 if (open_input_stream(c, info) < 0) {
1671 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1675 /* prepare HTTP header */
1677 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1678 mime_type = c->stream->fmt->mime_type;
1680 mime_type = "application/x-octet-stream";
1681 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1683 /* for asf, we need extra headers */
1684 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1685 /* Need to allocate a client id */
1687 c->wmp_client_id = av_lfg_get(&random_state);
1689 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);
1691 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1692 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1693 q = c->buffer + strlen(c->buffer);
1695 /* prepare output buffer */
1697 c->buffer_ptr = c->buffer;
1699 c->state = HTTPSTATE_SEND_HEADER;
1702 c->http_error = 404;
1705 snprintf(q, c->buffer_size,
1706 "HTTP/1.0 404 Not Found\r\n"
1707 "Content-type: text/html\r\n"
1710 "<head><title>404 Not Found</title></head>\n"
1714 /* prepare output buffer */
1715 c->buffer_ptr = c->buffer;
1717 c->state = HTTPSTATE_SEND_HEADER;
1721 c->http_error = 200; /* horrible : we use this value to avoid
1722 going to the send data state */
1723 c->state = HTTPSTATE_SEND_HEADER;
1727 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1729 static const char suffix[] = " kMGTP";
1732 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1734 avio_printf(pb, "%"PRId64"%c", count, *s);
1737 static void compute_status(HTTPContext *c)
1740 FFServerStream *stream;
1746 if (avio_open_dyn_buf(&pb) < 0) {
1747 /* XXX: return an error ? */
1748 c->buffer_ptr = c->buffer;
1749 c->buffer_end = c->buffer;
1753 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1754 avio_printf(pb, "Content-type: text/html\r\n");
1755 avio_printf(pb, "Pragma: no-cache\r\n");
1756 avio_printf(pb, "\r\n");
1758 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1759 if (c->stream->feed_filename[0])
1760 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1761 avio_printf(pb, "</head>\n<body>");
1762 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1764 avio_printf(pb, "<h2>Available Streams</h2>\n");
1765 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1766 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");
1767 stream = config.first_stream;
1769 char sfilename[1024];
1772 if (stream->feed != stream) {
1773 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1774 eosf = sfilename + strlen(sfilename);
1775 if (eosf - sfilename >= 4) {
1776 if (strcmp(eosf - 4, ".asf") == 0)
1777 strcpy(eosf - 4, ".asx");
1778 else if (strcmp(eosf - 3, ".rm") == 0)
1779 strcpy(eosf - 3, ".ram");
1780 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1781 /* generate a sample RTSP director if
1782 unicast. Generate an SDP redirector if
1784 eosf = strrchr(sfilename, '.');
1786 eosf = sfilename + strlen(sfilename);
1787 if (stream->is_multicast)
1788 strcpy(eosf, ".sdp");
1790 strcpy(eosf, ".rtsp");
1794 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1795 sfilename, stream->filename);
1796 avio_printf(pb, "<td align=right> %d <td align=right> ",
1797 stream->conns_served);
1798 fmt_bytecount(pb, stream->bytes_served);
1799 switch(stream->stream_type) {
1800 case STREAM_TYPE_LIVE: {
1801 int audio_bit_rate = 0;
1802 int video_bit_rate = 0;
1803 const char *audio_codec_name = "";
1804 const char *video_codec_name = "";
1805 const char *audio_codec_name_extra = "";
1806 const char *video_codec_name_extra = "";
1808 for(i=0;i<stream->nb_streams;i++) {
1809 AVStream *st = stream->streams[i];
1810 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1811 switch(st->codec->codec_type) {
1812 case AVMEDIA_TYPE_AUDIO:
1813 audio_bit_rate += st->codec->bit_rate;
1815 if (*audio_codec_name)
1816 audio_codec_name_extra = "...";
1817 audio_codec_name = codec->name;
1820 case AVMEDIA_TYPE_VIDEO:
1821 video_bit_rate += st->codec->bit_rate;
1823 if (*video_codec_name)
1824 video_codec_name_extra = "...";
1825 video_codec_name = codec->name;
1828 case AVMEDIA_TYPE_DATA:
1829 video_bit_rate += st->codec->bit_rate;
1835 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",
1838 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1839 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1841 avio_printf(pb, "<td>%s", stream->feed->filename);
1843 avio_printf(pb, "<td>%s", stream->feed_filename);
1844 avio_printf(pb, "\n");
1848 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1852 stream = stream->next;
1854 avio_printf(pb, "</table>\n");
1856 stream = config.first_stream;
1858 if (stream->feed == stream) {
1859 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1861 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1868 /* This is somewhat linux specific I guess */
1869 snprintf(ps_cmd, sizeof(ps_cmd),
1870 "ps -o \"%%cpu,cputime\" --no-headers %d",
1873 pid_stat = popen(ps_cmd, "r");
1878 if (fscanf(pid_stat, "%9s %63s", cpuperc,
1880 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
1888 avio_printf(pb, "<p>");
1890 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");
1892 for (i = 0; i < stream->nb_streams; i++) {
1893 AVStream *st = stream->streams[i];
1894 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1895 const char *type = "unknown";
1896 char parameters[64];
1900 switch(st->codec->codec_type) {
1901 case AVMEDIA_TYPE_AUDIO:
1903 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
1905 case AVMEDIA_TYPE_VIDEO:
1907 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
1908 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
1913 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
1914 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
1916 avio_printf(pb, "</table>\n");
1919 stream = stream->next;
1922 /* connection status */
1923 avio_printf(pb, "<h2>Connection Status</h2>\n");
1925 avio_printf(pb, "Number of connections: %d / %d<br>\n",
1926 nb_connections, config.nb_max_connections);
1928 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
1929 current_bandwidth, config.max_bandwidth);
1931 avio_printf(pb, "<table>\n");
1932 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");
1933 c1 = first_http_ctx;
1941 for (j = 0; j < c1->stream->nb_streams; j++) {
1942 if (!c1->stream->feed)
1943 bitrate += c1->stream->streams[j]->codec->bit_rate;
1944 else if (c1->feed_streams[j] >= 0)
1945 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
1950 p = inet_ntoa(c1->from_addr.sin_addr);
1951 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
1953 c1->stream ? c1->stream->filename : "",
1954 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
1957 http_state[c1->state]);
1958 fmt_bytecount(pb, bitrate);
1959 avio_printf(pb, "<td align=right>");
1960 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
1961 avio_printf(pb, "<td align=right>");
1962 fmt_bytecount(pb, c1->data_count);
1963 avio_printf(pb, "\n");
1966 avio_printf(pb, "</table>\n");
1971 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
1972 avio_printf(pb, "</body>\n</html>\n");
1974 len = avio_close_dyn_buf(pb, &c->pb_buffer);
1975 c->buffer_ptr = c->pb_buffer;
1976 c->buffer_end = c->pb_buffer + len;
1979 static int open_input_stream(HTTPContext *c, const char *info)
1982 char input_filename[1024];
1983 AVFormatContext *s = NULL;
1984 int buf_size, i, ret;
1987 /* find file name */
1988 if (c->stream->feed) {
1989 strcpy(input_filename, c->stream->feed->feed_filename);
1990 buf_size = FFM_PACKET_SIZE;
1991 /* compute position (absolute time) */
1992 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
1993 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
1994 http_log("Invalid date specification '%s' for stream\n", buf);
1997 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
1998 int prebuffer = strtol(buf, 0, 10);
1999 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2001 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2003 strcpy(input_filename, c->stream->feed_filename);
2005 /* compute position (relative time) */
2006 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2007 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2008 http_log("Invalid date specification '%s' for stream\n", buf);
2014 if (!input_filename[0]) {
2015 http_log("No filename was specified for stream\n");
2016 return AVERROR(EINVAL);
2020 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2021 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2025 /* set buffer size */
2026 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2028 s->flags |= AVFMT_FLAG_GENPTS;
2030 if (strcmp(s->iformat->name, "ffm") &&
2031 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2032 http_log("Could not find stream info for input '%s'\n", input_filename);
2033 avformat_close_input(&s);
2037 /* choose stream as clock source (we favor the video stream if
2038 * present) for packet sending */
2039 c->pts_stream_index = 0;
2040 for(i=0;i<c->stream->nb_streams;i++) {
2041 if (c->pts_stream_index == 0 &&
2042 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2043 c->pts_stream_index = i;
2047 if (c->fmt_in->iformat->read_seek)
2048 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2049 /* set the start time (needed for maxtime and RTP packet timing) */
2050 c->start_time = cur_time;
2051 c->first_pts = AV_NOPTS_VALUE;
2055 /* return the server clock (in us) */
2056 static int64_t get_server_clock(HTTPContext *c)
2058 /* compute current pts value from system time */
2059 return (cur_time - c->start_time) * 1000;
2062 /* return the estimated time at which the current packet must be sent
2064 static int64_t get_packet_send_clock(HTTPContext *c)
2066 int bytes_left, bytes_sent, frame_bytes;
2068 frame_bytes = c->cur_frame_bytes;
2069 if (frame_bytes <= 0)
2072 bytes_left = c->buffer_end - c->buffer_ptr;
2073 bytes_sent = frame_bytes - bytes_left;
2074 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2079 static int http_prepare_data(HTTPContext *c)
2082 AVFormatContext *ctx;
2084 av_freep(&c->pb_buffer);
2086 case HTTPSTATE_SEND_DATA_HEADER:
2087 ctx = avformat_alloc_context();
2090 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2091 c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams, sizeof(AVStream *));
2093 for(i=0;i<c->stream->nb_streams;i++) {
2095 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2096 /* if file or feed, then just take streams from FFServerStream struct */
2097 if (!c->stream->feed ||
2098 c->stream->feed == c->stream)
2099 src = c->stream->streams[i];
2101 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2103 *(c->fmt_ctx.streams[i]) = *src;
2104 c->fmt_ctx.streams[i]->priv_data = 0;
2105 /* XXX: should be done in AVStream, not in codec */
2106 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2108 /* set output format parameters */
2109 c->fmt_ctx.oformat = c->stream->fmt;
2110 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2112 c->got_key_frame = 0;
2114 /* prepare header and save header data in a stream */
2115 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2116 /* XXX: potential leak */
2119 c->fmt_ctx.pb->seekable = 0;
2122 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2123 * Default value from FFmpeg
2124 * Try to set it using configuration option
2126 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2128 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2129 http_log("Error writing output header for stream '%s': %s\n",
2130 c->stream->filename, av_err2str(ret));
2133 av_dict_free(&c->fmt_ctx.metadata);
2135 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2136 c->buffer_ptr = c->pb_buffer;
2137 c->buffer_end = c->pb_buffer + len;
2139 c->state = HTTPSTATE_SEND_DATA;
2140 c->last_packet_sent = 0;
2142 case HTTPSTATE_SEND_DATA:
2143 /* find a new packet */
2144 /* read a packet from the input stream */
2145 if (c->stream->feed)
2146 ffm_set_write_index(c->fmt_in,
2147 c->stream->feed->feed_write_index,
2148 c->stream->feed->feed_size);
2150 if (c->stream->max_time &&
2151 c->stream->max_time + c->start_time - cur_time < 0)
2152 /* We have timed out */
2153 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2157 ret = av_read_frame(c->fmt_in, &pkt);
2159 if (c->stream->feed) {
2160 /* if coming from feed, it means we reached the end of the
2161 ffm file, so must wait for more data */
2162 c->state = HTTPSTATE_WAIT_FEED;
2163 return 1; /* state changed */
2164 } else if (ret == AVERROR(EAGAIN)) {
2165 /* input not ready, come back later */
2168 if (c->stream->loop) {
2169 avformat_close_input(&c->fmt_in);
2170 if (open_input_stream(c, "") < 0)
2175 /* must send trailer now because EOF or error */
2176 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2180 int source_index = pkt.stream_index;
2181 /* update first pts if needed */
2182 if (c->first_pts == AV_NOPTS_VALUE) {
2183 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2184 c->start_time = cur_time;
2186 /* send it to the appropriate stream */
2187 if (c->stream->feed) {
2188 /* if coming from a feed, select the right stream */
2189 if (c->switch_pending) {
2190 c->switch_pending = 0;
2191 for(i=0;i<c->stream->nb_streams;i++) {
2192 if (c->switch_feed_streams[i] == pkt.stream_index)
2193 if (pkt.flags & AV_PKT_FLAG_KEY)
2194 c->switch_feed_streams[i] = -1;
2195 if (c->switch_feed_streams[i] >= 0)
2196 c->switch_pending = 1;
2199 for(i=0;i<c->stream->nb_streams;i++) {
2200 if (c->stream->feed_streams[i] == pkt.stream_index) {
2201 AVStream *st = c->fmt_in->streams[source_index];
2202 pkt.stream_index = i;
2203 if (pkt.flags & AV_PKT_FLAG_KEY &&
2204 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2205 c->stream->nb_streams == 1))
2206 c->got_key_frame = 1;
2207 if (!c->stream->send_on_key || c->got_key_frame)
2212 AVCodecContext *codec;
2213 AVStream *ist, *ost;
2215 ist = c->fmt_in->streams[source_index];
2216 /* specific handling for RTP: we use several
2217 * output streams (one for each RTP connection).
2218 * XXX: need more abstract handling */
2219 if (c->is_packetized) {
2220 /* compute send time and duration */
2221 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2222 c->cur_pts -= c->first_pts;
2223 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2224 /* find RTP context */
2225 c->packet_stream_index = pkt.stream_index;
2226 ctx = c->rtp_ctx[c->packet_stream_index];
2228 av_free_packet(&pkt);
2231 codec = ctx->streams[0]->codec;
2232 /* only one stream per RTP connection */
2233 pkt.stream_index = 0;
2237 codec = ctx->streams[pkt.stream_index]->codec;
2240 if (c->is_packetized) {
2241 int max_packet_size;
2242 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2243 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2245 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2246 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2248 ret = avio_open_dyn_buf(&ctx->pb);
2251 /* XXX: potential leak */
2254 ost = ctx->streams[pkt.stream_index];
2256 ctx->pb->seekable = 0;
2257 if (pkt.dts != AV_NOPTS_VALUE)
2258 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2259 if (pkt.pts != AV_NOPTS_VALUE)
2260 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2261 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2262 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2263 http_log("Error writing frame to output for stream '%s': %s\n",
2264 c->stream->filename, av_err2str(ret));
2265 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2268 av_freep(&c->pb_buffer);
2269 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2270 c->cur_frame_bytes = len;
2271 c->buffer_ptr = c->pb_buffer;
2272 c->buffer_end = c->pb_buffer + len;
2274 codec->frame_number++;
2276 av_free_packet(&pkt);
2280 av_free_packet(&pkt);
2285 case HTTPSTATE_SEND_DATA_TRAILER:
2286 /* last packet test ? */
2287 if (c->last_packet_sent || c->is_packetized)
2290 /* prepare header */
2291 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2292 /* XXX: potential leak */
2295 c->fmt_ctx.pb->seekable = 0;
2296 av_write_trailer(ctx);
2297 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2298 c->buffer_ptr = c->pb_buffer;
2299 c->buffer_end = c->pb_buffer + len;
2301 c->last_packet_sent = 1;
2307 /* should convert the format at the same time */
2308 /* send data starting at c->buffer_ptr to the output connection
2309 * (either UDP or TCP) */
2310 static int http_send_data(HTTPContext *c)
2315 if (c->buffer_ptr >= c->buffer_end) {
2316 ret = http_prepare_data(c);
2320 /* state change requested */
2323 if (c->is_packetized) {
2324 /* RTP data output */
2325 len = c->buffer_end - c->buffer_ptr;
2327 /* fail safe - should never happen */
2329 c->buffer_ptr = c->buffer_end;
2332 len = (c->buffer_ptr[0] << 24) |
2333 (c->buffer_ptr[1] << 16) |
2334 (c->buffer_ptr[2] << 8) |
2336 if (len > (c->buffer_end - c->buffer_ptr))
2338 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2339 /* nothing to send yet: we can wait */
2343 c->data_count += len;
2344 update_datarate(&c->datarate, c->data_count);
2346 c->stream->bytes_served += len;
2348 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2349 /* RTP packets are sent inside the RTSP TCP connection */
2351 int interleaved_index, size;
2353 HTTPContext *rtsp_c;
2356 /* if no RTSP connection left, error */
2359 /* if already sending something, then wait. */
2360 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2362 if (avio_open_dyn_buf(&pb) < 0)
2364 interleaved_index = c->packet_stream_index * 2;
2365 /* RTCP packets are sent at odd indexes */
2366 if (c->buffer_ptr[1] == 200)
2367 interleaved_index++;
2368 /* write RTSP TCP header */
2370 header[1] = interleaved_index;
2371 header[2] = len >> 8;
2373 avio_write(pb, header, 4);
2374 /* write RTP packet data */
2376 avio_write(pb, c->buffer_ptr, len);
2377 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2378 /* prepare asynchronous TCP sending */
2379 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2380 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2381 c->buffer_ptr += len;
2383 /* send everything we can NOW */
2384 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2385 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2387 rtsp_c->packet_buffer_ptr += len;
2388 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2389 /* if we could not send all the data, we will
2390 send it later, so a new state is needed to
2391 "lock" the RTSP TCP connection */
2392 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2395 /* all data has been sent */
2396 av_freep(&c->packet_buffer);
2398 /* send RTP packet directly in UDP */
2400 ffurl_write(c->rtp_handles[c->packet_stream_index],
2401 c->buffer_ptr, len);
2402 c->buffer_ptr += len;
2403 /* here we continue as we can send several packets per 10 ms slot */
2406 /* TCP data output */
2407 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2409 if (ff_neterrno() != AVERROR(EAGAIN) &&
2410 ff_neterrno() != AVERROR(EINTR))
2411 /* error : close connection */
2416 c->buffer_ptr += len;
2418 c->data_count += len;
2419 update_datarate(&c->datarate, c->data_count);
2421 c->stream->bytes_served += len;
2429 static int http_start_receive_data(HTTPContext *c)
2434 if (c->stream->feed_opened) {
2435 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2436 return AVERROR(EINVAL);
2439 /* Don't permit writing to this one */
2440 if (c->stream->readonly) {
2441 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2442 return AVERROR(EINVAL);
2446 fd = open(c->stream->feed_filename, O_RDWR);
2448 ret = AVERROR(errno);
2449 http_log("Could not open feed file '%s': %s\n",
2450 c->stream->feed_filename, strerror(errno));
2455 if (c->stream->truncate) {
2456 /* truncate feed file */
2457 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2458 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2459 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2460 ret = AVERROR(errno);
2461 http_log("Error truncating feed file '%s': %s\n",
2462 c->stream->feed_filename, strerror(errno));
2466 ret = ffm_read_write_index(fd);
2468 http_log("Error reading write index from feed file '%s': %s\n",
2469 c->stream->feed_filename, strerror(errno));
2472 c->stream->feed_write_index = ret;
2476 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2477 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2478 lseek(fd, 0, SEEK_SET);
2480 /* init buffer input */
2481 c->buffer_ptr = c->buffer;
2482 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2483 c->stream->feed_opened = 1;
2484 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2488 static int http_receive_data(HTTPContext *c)
2491 int len, loop_run = 0;
2493 while (c->chunked_encoding && !c->chunk_size &&
2494 c->buffer_end > c->buffer_ptr) {
2495 /* read chunk header, if present */
2496 len = recv(c->fd, c->buffer_ptr, 1, 0);
2499 if (ff_neterrno() != AVERROR(EAGAIN) &&
2500 ff_neterrno() != AVERROR(EINTR))
2501 /* error : close connection */
2504 } else if (len == 0) {
2505 /* end of connection : close it */
2507 } else if (c->buffer_ptr - c->buffer >= 2 &&
2508 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2509 c->chunk_size = strtol(c->buffer, 0, 16);
2510 if (c->chunk_size == 0) // end of stream
2512 c->buffer_ptr = c->buffer;
2514 } else if (++loop_run > 10) {
2515 /* no chunk header, abort */
2522 if (c->buffer_end > c->buffer_ptr) {
2523 len = recv(c->fd, c->buffer_ptr,
2524 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2526 if (ff_neterrno() != AVERROR(EAGAIN) &&
2527 ff_neterrno() != AVERROR(EINTR))
2528 /* error : close connection */
2530 } else if (len == 0)
2531 /* end of connection : close it */
2534 c->chunk_size -= len;
2535 c->buffer_ptr += len;
2536 c->data_count += len;
2537 update_datarate(&c->datarate, c->data_count);
2541 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2542 if (c->buffer[0] != 'f' ||
2543 c->buffer[1] != 'm') {
2544 http_log("Feed stream has become desynchronized -- disconnecting\n");
2549 if (c->buffer_ptr >= c->buffer_end) {
2550 FFServerStream *feed = c->stream;
2551 /* a packet has been received : write it in the store, except
2553 if (c->data_count > FFM_PACKET_SIZE) {
2554 /* XXX: use llseek or url_seek
2555 * XXX: Should probably fail? */
2556 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2557 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2559 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2560 http_log("Error writing to feed file: %s\n", strerror(errno));
2564 feed->feed_write_index += FFM_PACKET_SIZE;
2565 /* update file size */
2566 if (feed->feed_write_index > c->stream->feed_size)
2567 feed->feed_size = feed->feed_write_index;
2569 /* handle wrap around if max file size reached */
2570 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2571 feed->feed_write_index = FFM_PACKET_SIZE;
2574 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2575 http_log("Error writing index to feed file: %s\n", strerror(errno));
2579 /* wake up any waiting connections */
2580 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2581 if (c1->state == HTTPSTATE_WAIT_FEED &&
2582 c1->stream->feed == c->stream->feed)
2583 c1->state = HTTPSTATE_SEND_DATA;
2586 /* We have a header in our hands that contains useful data */
2587 AVFormatContext *s = avformat_alloc_context();
2589 AVInputFormat *fmt_in;
2595 /* use feed output format name to find corresponding input format */
2596 fmt_in = av_find_input_format(feed->fmt->name);
2600 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2601 0, NULL, NULL, NULL, NULL);
2605 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2610 /* Now we have the actual streams */
2611 if (s->nb_streams != feed->nb_streams) {
2612 avformat_close_input(&s);
2614 http_log("Feed '%s' stream number does not match registered feed\n",
2615 c->stream->feed_filename);
2619 for (i = 0; i < s->nb_streams; i++) {
2620 AVStream *fst = feed->streams[i];
2621 AVStream *st = s->streams[i];
2622 avcodec_copy_context(fst->codec, st->codec);
2625 avformat_close_input(&s);
2628 c->buffer_ptr = c->buffer;
2633 c->stream->feed_opened = 0;
2635 /* wake up any waiting connections to stop waiting for feed */
2636 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2637 if (c1->state == HTTPSTATE_WAIT_FEED &&
2638 c1->stream->feed == c->stream->feed)
2639 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2644 /********************************************************************/
2647 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2654 str = RTSP_STATUS_CODE2STRING(error_number);
2656 str = "Unknown Error";
2658 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2659 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2661 /* output GMT time */
2664 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2665 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2668 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2670 rtsp_reply_header(c, error_number);
2671 avio_printf(c->pb, "\r\n");
2674 static int rtsp_parse_request(HTTPContext *c)
2676 const char *p, *p1, *p2;
2682 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2684 c->buffer_ptr[0] = '\0';
2687 get_word(cmd, sizeof(cmd), &p);
2688 get_word(url, sizeof(url), &p);
2689 get_word(protocol, sizeof(protocol), &p);
2691 av_strlcpy(c->method, cmd, sizeof(c->method));
2692 av_strlcpy(c->url, url, sizeof(c->url));
2693 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2695 if (avio_open_dyn_buf(&c->pb) < 0) {
2696 /* XXX: cannot do more */
2697 c->pb = NULL; /* safety */
2701 /* check version name */
2702 if (strcmp(protocol, "RTSP/1.0")) {
2703 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2707 /* parse each header line */
2708 /* skip to next line */
2709 while (*p != '\n' && *p != '\0')
2713 while (*p != '\0') {
2714 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2718 if (p2 > p && p2[-1] == '\r')
2720 /* skip empty line */
2724 if (len > sizeof(line) - 1)
2725 len = sizeof(line) - 1;
2726 memcpy(line, p, len);
2728 ff_rtsp_parse_line(header, line, NULL, NULL);
2732 /* handle sequence number */
2733 c->seq = header->seq;
2735 if (!strcmp(cmd, "DESCRIBE"))
2736 rtsp_cmd_describe(c, url);
2737 else if (!strcmp(cmd, "OPTIONS"))
2738 rtsp_cmd_options(c, url);
2739 else if (!strcmp(cmd, "SETUP"))
2740 rtsp_cmd_setup(c, url, header);
2741 else if (!strcmp(cmd, "PLAY"))
2742 rtsp_cmd_play(c, url, header);
2743 else if (!strcmp(cmd, "PAUSE"))
2744 rtsp_cmd_interrupt(c, url, header, 1);
2745 else if (!strcmp(cmd, "TEARDOWN"))
2746 rtsp_cmd_interrupt(c, url, header, 0);
2748 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2751 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2752 c->pb = NULL; /* safety */
2754 /* XXX: cannot do more */
2757 c->buffer_ptr = c->pb_buffer;
2758 c->buffer_end = c->pb_buffer + len;
2759 c->state = RTSPSTATE_SEND_REPLY;
2763 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2764 struct in_addr my_ip)
2766 AVFormatContext *avc;
2767 AVStream *avs = NULL;
2768 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2769 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2774 avc = avformat_alloc_context();
2775 if (!avc || !rtp_format) {
2778 avc->oformat = rtp_format;
2779 av_dict_set(&avc->metadata, "title",
2780 entry ? entry->value : "No Title", 0);
2781 avc->nb_streams = stream->nb_streams;
2782 if (stream->is_multicast) {
2783 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2784 inet_ntoa(stream->multicast_ip),
2785 stream->multicast_port, stream->multicast_ttl);
2787 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2790 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2791 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2793 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2794 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2797 for(i = 0; i < stream->nb_streams; i++) {
2798 avc->streams[i] = &avs[i];
2799 avc->streams[i]->codec = stream->streams[i]->codec;
2801 *pbuffer = av_mallocz(2048);
2802 av_sdp_create(&avc, 1, *pbuffer, 2048);
2805 av_freep(&avc->streams);
2806 av_dict_free(&avc->metadata);
2810 return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2813 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2815 // rtsp_reply_header(c, RTSP_STATUS_OK);
2816 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2817 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2818 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2819 avio_printf(c->pb, "\r\n");
2822 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2824 FFServerStream *stream;
2830 struct sockaddr_in my_addr;
2832 /* find which URL is asked */
2833 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2838 for(stream = config.first_stream; stream; stream = stream->next) {
2839 if (!stream->is_feed &&
2840 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2841 !strcmp(path, stream->filename)) {
2845 /* no stream found */
2846 rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
2850 /* prepare the media description in SDP format */
2852 /* get the host IP */
2853 len = sizeof(my_addr);
2854 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2855 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2856 if (content_length < 0) {
2857 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2860 rtsp_reply_header(c, RTSP_STATUS_OK);
2861 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2862 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2863 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2864 avio_printf(c->pb, "\r\n");
2865 avio_write(c->pb, content, content_length);
2869 static HTTPContext *find_rtp_session(const char *session_id)
2873 if (session_id[0] == '\0')
2876 for(c = first_http_ctx; c; c = c->next) {
2877 if (!strcmp(c->session_id, session_id))
2883 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2885 RTSPTransportField *th;
2888 for(i=0;i<h->nb_transports;i++) {
2889 th = &h->transports[i];
2890 if (th->lower_transport == lower_transport)
2896 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2897 RTSPMessageHeader *h)
2899 FFServerStream *stream;
2900 int stream_index, rtp_port, rtcp_port;
2905 RTSPTransportField *th;
2906 struct sockaddr_in dest_addr;
2907 RTSPActionServerSetup setup;
2909 /* find which URL is asked */
2910 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2915 /* now check each stream */
2916 for(stream = config.first_stream; stream; stream = stream->next) {
2917 if (!stream->is_feed &&
2918 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2919 /* accept aggregate filenames only if single stream */
2920 if (!strcmp(path, stream->filename)) {
2921 if (stream->nb_streams != 1) {
2922 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2929 for(stream_index = 0; stream_index < stream->nb_streams;
2931 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2932 stream->filename, stream_index);
2933 if (!strcmp(path, buf))
2938 /* no stream found */
2939 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2943 /* generate session id if needed */
2944 if (h->session_id[0] == '\0') {
2945 unsigned random0 = av_lfg_get(&random_state);
2946 unsigned random1 = av_lfg_get(&random_state);
2947 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2951 /* find RTP session, and create it if none found */
2952 rtp_c = find_rtp_session(h->session_id);
2954 /* always prefer UDP */
2955 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2957 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2959 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2964 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2965 th->lower_transport);
2967 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2971 /* open input stream */
2972 if (open_input_stream(rtp_c, "") < 0) {
2973 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2978 /* test if stream is OK (test needed because several SETUP needs
2979 to be done for a given file) */
2980 if (rtp_c->stream != stream) {
2981 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2985 /* test if stream is already set up */
2986 if (rtp_c->rtp_ctx[stream_index]) {
2987 rtsp_reply_error(c, RTSP_STATUS_STATE);
2991 /* check transport */
2992 th = find_transport(h, rtp_c->rtp_protocol);
2993 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2994 th->client_port_min <= 0)) {
2995 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2999 /* setup default options */
3000 setup.transport_option[0] = '\0';
3001 dest_addr = rtp_c->from_addr;
3002 dest_addr.sin_port = htons(th->client_port_min);
3005 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3006 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3010 /* now everything is OK, so we can send the connection parameters */
3011 rtsp_reply_header(c, RTSP_STATUS_OK);
3013 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3015 switch(rtp_c->rtp_protocol) {
3016 case RTSP_LOWER_TRANSPORT_UDP:
3017 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3018 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3019 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3020 "client_port=%d-%d;server_port=%d-%d",
3021 th->client_port_min, th->client_port_max,
3022 rtp_port, rtcp_port);
3024 case RTSP_LOWER_TRANSPORT_TCP:
3025 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3026 stream_index * 2, stream_index * 2 + 1);
3031 if (setup.transport_option[0] != '\0')
3032 avio_printf(c->pb, ";%s", setup.transport_option);
3033 avio_printf(c->pb, "\r\n");
3036 avio_printf(c->pb, "\r\n");
3040 /* find an RTP connection by using the session ID. Check consistency
3042 static HTTPContext *find_rtp_session_with_url(const char *url,
3043 const char *session_id)
3051 rtp_c = find_rtp_session(session_id);
3055 /* find which URL is asked */
3056 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3060 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3061 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3062 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3063 rtp_c->stream->filename, s);
3064 if(!strncmp(path, buf, sizeof(buf))) {
3065 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3070 if (len > 0 && path[len - 1] == '/' &&
3071 !strncmp(path, rtp_c->stream->filename, len - 1))
3076 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3080 rtp_c = find_rtp_session_with_url(url, h->session_id);
3082 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3086 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3087 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3088 rtp_c->state != HTTPSTATE_READY) {
3089 rtsp_reply_error(c, RTSP_STATUS_STATE);
3093 rtp_c->state = HTTPSTATE_SEND_DATA;
3095 /* now everything is OK, so we can send the connection parameters */
3096 rtsp_reply_header(c, RTSP_STATUS_OK);
3098 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3099 avio_printf(c->pb, "\r\n");
3102 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3106 rtp_c = find_rtp_session_with_url(url, h->session_id);
3108 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3113 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3114 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3115 rtsp_reply_error(c, RTSP_STATUS_STATE);
3118 rtp_c->state = HTTPSTATE_READY;
3119 rtp_c->first_pts = AV_NOPTS_VALUE;
3122 /* now everything is OK, so we can send the connection parameters */
3123 rtsp_reply_header(c, RTSP_STATUS_OK);
3125 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3126 avio_printf(c->pb, "\r\n");
3129 close_connection(rtp_c);
3132 /********************************************************************/
3135 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3136 FFServerStream *stream, const char *session_id,
3137 enum RTSPLowerTransport rtp_protocol)
3139 HTTPContext *c = NULL;
3140 const char *proto_str;
3142 /* XXX: should output a warning page when coming
3143 close to the connection limit */
3144 if (nb_connections >= config.nb_max_connections)
3147 /* add a new connection */
3148 c = av_mallocz(sizeof(HTTPContext));
3153 c->poll_entry = NULL;
3154 c->from_addr = *from_addr;
3155 c->buffer_size = IOBUFFER_INIT_SIZE;
3156 c->buffer = av_malloc(c->buffer_size);
3161 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3162 c->state = HTTPSTATE_READY;
3163 c->is_packetized = 1;
3164 c->rtp_protocol = rtp_protocol;
3166 /* protocol is shown in statistics */
3167 switch(c->rtp_protocol) {
3168 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3169 proto_str = "MCAST";
3171 case RTSP_LOWER_TRANSPORT_UDP:
3174 case RTSP_LOWER_TRANSPORT_TCP:
3181 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3182 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3184 current_bandwidth += stream->bandwidth;
3186 c->next = first_http_ctx;
3192 av_freep(&c->buffer);
3198 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3199 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3201 static int rtp_new_av_stream(HTTPContext *c,
3202 int stream_index, struct sockaddr_in *dest_addr,
3203 HTTPContext *rtsp_c)
3205 AVFormatContext *ctx;
3208 URLContext *h = NULL;
3210 int max_packet_size;
3212 /* now we can open the relevant output stream */
3213 ctx = avformat_alloc_context();
3216 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3218 st = av_mallocz(sizeof(AVStream));
3221 ctx->nb_streams = 1;
3222 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3225 ctx->streams[0] = st;
3227 if (!c->stream->feed ||
3228 c->stream->feed == c->stream)
3229 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3232 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3234 st->priv_data = NULL;
3236 /* build destination RTP address */
3237 ipaddr = inet_ntoa(dest_addr->sin_addr);
3239 switch(c->rtp_protocol) {
3240 case RTSP_LOWER_TRANSPORT_UDP:
3241 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3244 /* XXX: also pass as parameter to function ? */
3245 if (c->stream->is_multicast) {
3247 ttl = c->stream->multicast_ttl;
3250 snprintf(ctx->filename, sizeof(ctx->filename),
3251 "rtp://%s:%d?multicast=1&ttl=%d",
3252 ipaddr, ntohs(dest_addr->sin_port), ttl);
3254 snprintf(ctx->filename, sizeof(ctx->filename),
3255 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3258 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3260 c->rtp_handles[stream_index] = h;
3261 max_packet_size = h->max_packet_size;
3263 case RTSP_LOWER_TRANSPORT_TCP:
3266 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3272 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3273 ipaddr, ntohs(dest_addr->sin_port),
3274 c->stream->filename, stream_index, c->protocol);
3276 /* normally, no packets should be output here, but the packet size may
3278 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3279 /* XXX: close stream */
3282 if (avformat_write_header(ctx, NULL) < 0) {
3290 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3293 c->rtp_ctx[stream_index] = ctx;
3297 /********************************************************************/
3298 /* ffserver initialization */
3300 static AVStream *add_av_stream1(FFServerStream *stream, AVCodecContext *codec, int copy)
3304 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3307 fst = av_mallocz(sizeof(AVStream));
3311 fst->codec = avcodec_alloc_context3(codec->codec);
3312 avcodec_copy_context(fst->codec, codec);
3314 /* live streams must use the actual feed's codec since it may be
3315 * updated later to carry extradata needed by them.
3319 fst->priv_data = av_mallocz(sizeof(FeedData));
3320 fst->index = stream->nb_streams;
3321 avpriv_set_pts_info(fst, 33, 1, 90000);
3322 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3323 stream->streams[stream->nb_streams++] = fst;
3327 /* return the stream number in the feed */
3328 static int add_av_stream(FFServerStream *feed, AVStream *st)
3331 AVCodecContext *av, *av1;
3335 for(i=0;i<feed->nb_streams;i++) {
3336 av1 = feed->streams[i]->codec;
3337 if (av1->codec_id == av->codec_id &&
3338 av1->codec_type == av->codec_type &&
3339 av1->bit_rate == av->bit_rate) {
3341 switch(av->codec_type) {
3342 case AVMEDIA_TYPE_AUDIO:
3343 if (av1->channels == av->channels &&
3344 av1->sample_rate == av->sample_rate)
3347 case AVMEDIA_TYPE_VIDEO:
3348 if (av1->width == av->width &&
3349 av1->height == av->height &&
3350 av1->time_base.den == av->time_base.den &&
3351 av1->time_base.num == av->time_base.num &&
3352 av1->gop_size == av->gop_size)
3361 fst = add_av_stream1(feed, av, 0);
3364 if (av_stream_get_recommended_encoder_configuration(st))
3365 av_stream_set_recommended_encoder_configuration(fst,
3366 av_strdup(av_stream_get_recommended_encoder_configuration(st)));
3367 return feed->nb_streams - 1;
3370 static void remove_stream(FFServerStream *stream)
3372 FFServerStream **ps;
3373 ps = &config.first_stream;
3382 /* specific MPEG4 handling : we extract the raw parameters */
3383 static void extract_mpeg4_header(AVFormatContext *infile)
3385 int mpeg4_count, i, size;
3390 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3393 for(i=0;i<infile->nb_streams;i++) {
3394 st = infile->streams[i];
3395 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3396 st->codec->extradata_size == 0) {
3403 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3404 while (mpeg4_count > 0) {
3405 if (av_read_frame(infile, &pkt) < 0)
3407 st = infile->streams[pkt.stream_index];
3408 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3409 st->codec->extradata_size == 0) {
3410 av_freep(&st->codec->extradata);
3411 /* fill extradata with the header */
3412 /* XXX: we make hard suppositions here ! */
3414 while (p < pkt.data + pkt.size - 4) {
3415 /* stop when vop header is found */
3416 if (p[0] == 0x00 && p[1] == 0x00 &&
3417 p[2] == 0x01 && p[3] == 0xb6) {
3418 size = p - pkt.data;
3419 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3420 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3421 st->codec->extradata_size = size;
3422 memcpy(st->codec->extradata, pkt.data, size);
3429 av_free_packet(&pkt);
3433 /* compute the needed AVStream for each file */
3434 static void build_file_streams(void)
3436 FFServerStream *stream, *stream_next;
3439 /* gather all streams */
3440 for(stream = config.first_stream; stream; stream = stream_next) {
3441 AVFormatContext *infile = NULL;
3442 stream_next = stream->next;
3443 if (stream->stream_type == STREAM_TYPE_LIVE &&
3445 /* the stream comes from a file */
3446 /* try to open the file */
3448 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3449 /* specific case : if transport stream output to RTP,
3450 we use a raw transport stream reader */
3451 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3454 if (!stream->feed_filename[0]) {
3455 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3459 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3460 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3461 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3462 /* remove stream (no need to spend more time on it) */
3464 remove_stream(stream);
3466 /* find all the AVStreams inside and reference them in
3468 if (avformat_find_stream_info(infile, NULL) < 0) {
3469 http_log("Could not find codec parameters from '%s'\n",
3470 stream->feed_filename);
3471 avformat_close_input(&infile);
3474 extract_mpeg4_header(infile);
3476 for(i=0;i<infile->nb_streams;i++)
3477 add_av_stream1(stream, infile->streams[i]->codec, 1);
3479 avformat_close_input(&infile);
3485 /* compute the needed AVStream for each feed */
3486 static void build_feed_streams(void)
3488 FFServerStream *stream, *feed;
3491 /* gather all streams */
3492 for(stream = config.first_stream; stream; stream = stream->next) {
3493 feed = stream->feed;
3495 if (stream->is_feed) {
3496 for(i=0;i<stream->nb_streams;i++)
3497 stream->feed_streams[i] = i;
3499 /* we handle a stream coming from a feed */
3500 for(i=0;i<stream->nb_streams;i++)
3501 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3506 /* create feed files if needed */
3507 for(feed = config.first_feed; feed; feed = feed->next_feed) {
3510 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3511 /* See if it matches */
3512 AVFormatContext *s = NULL;
3515 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3516 /* set buffer size */
3517 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3518 /* Now see if it matches */
3519 if (s->nb_streams == feed->nb_streams) {
3521 for(i=0;i<s->nb_streams;i++) {
3523 sf = feed->streams[i];
3526 if (sf->index != ss->index ||
3528 http_log("Index & Id do not match for stream %d (%s)\n",
3529 i, feed->feed_filename);
3532 AVCodecContext *ccf, *ccs;
3536 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3538 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3539 http_log("Codecs do not match for stream %d\n", i);
3541 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3542 http_log("Codec bitrates do not match for stream %d\n", i);
3544 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3545 if (CHECK_CODEC(time_base.den) ||
3546 CHECK_CODEC(time_base.num) ||
3547 CHECK_CODEC(width) ||
3548 CHECK_CODEC(height)) {
3549 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3552 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3553 if (CHECK_CODEC(sample_rate) ||
3554 CHECK_CODEC(channels) ||
3555 CHECK_CODEC(frame_size)) {
3556 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3560 http_log("Unknown codec type\n");
3568 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3569 feed->feed_filename, s->nb_streams, feed->nb_streams);
3571 avformat_close_input(&s);
3573 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3574 feed->feed_filename);
3577 if (feed->readonly) {
3578 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3579 feed->feed_filename);
3582 unlink(feed->feed_filename);
3585 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3586 AVFormatContext *s = avformat_alloc_context();
3588 if (feed->readonly) {
3589 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3590 feed->feed_filename);
3594 /* only write the header of the ffm file */
3595 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3596 http_log("Could not open output feed file '%s'\n",
3597 feed->feed_filename);
3600 s->oformat = feed->fmt;
3601 s->nb_streams = feed->nb_streams;
3602 s->streams = feed->streams;
3603 if (avformat_write_header(s, NULL) < 0) {
3604 http_log("Container doesn't support the required parameters\n");
3607 /* XXX: need better API */
3608 av_freep(&s->priv_data);
3612 avformat_free_context(s);
3614 /* get feed size and write index */
3615 fd = open(feed->feed_filename, O_RDONLY);
3617 http_log("Could not open output feed file '%s'\n",
3618 feed->feed_filename);
3622 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3623 feed->feed_size = lseek(fd, 0, SEEK_END);
3624 /* ensure that we do not wrap before the end of file */
3625 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3626 feed->feed_max_size = feed->feed_size;
3632 /* compute the bandwidth used by each stream */
3633 static void compute_bandwidth(void)
3637 FFServerStream *stream;
3639 for(stream = config.first_stream; stream; stream = stream->next) {
3641 for(i=0;i<stream->nb_streams;i++) {
3642 AVStream *st = stream->streams[i];
3643 switch(st->codec->codec_type) {
3644 case AVMEDIA_TYPE_AUDIO:
3645 case AVMEDIA_TYPE_VIDEO:
3646 bandwidth += st->codec->bit_rate;
3652 stream->bandwidth = (bandwidth + 999) / 1000;
3656 static void handle_child_exit(int sig)
3661 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3662 FFServerStream *feed;
3664 for (feed = config.first_feed; feed; feed = feed->next) {
3665 if (feed->pid == pid) {
3666 int uptime = time(0) - feed->pid_start;
3669 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
3672 /* Turn off any more restarts */
3673 ffserver_free_child_args(&feed->child_argv);
3678 need_to_start_children = 1;
3681 static void opt_debug(void)
3684 snprintf(config.logfilename, sizeof(config.logfilename), "-");
3687 void show_help_default(const char *opt, const char *arg)
3689 printf("usage: ffserver [options]\n"
3690 "Hyper fast multi format Audio/Video streaming server\n");
3692 show_help_options(options, "Main options:", 0, 0, 0);
3695 static const OptionDef options[] = {
3696 #include "cmdutils_common_opts.h"
3697 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3698 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3699 { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3703 int main(int argc, char **argv)
3705 struct sigaction sigact = { { 0 } };
3708 config.filename = av_strdup("/etc/ffserver.conf");
3710 parse_loglevel(argc, argv, options);
3712 avformat_network_init();
3714 show_banner(argc, argv, options);
3716 my_program_name = argv[0];
3718 parse_options(NULL, argc, argv, options, NULL);
3720 unsetenv("http_proxy"); /* Kill the http_proxy */
3722 av_lfg_init(&random_state, av_get_random_seed());
3724 sigact.sa_handler = handle_child_exit;
3725 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3726 sigaction(SIGCHLD, &sigact, 0);
3728 if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3729 fprintf(stderr, "Error reading configuration file '%s': %s\n",
3730 config.filename, av_err2str(ret));
3733 av_freep(&config.filename);
3735 /* open log file if needed */
3736 if (config.logfilename[0] != '\0') {
3737 if (!strcmp(config.logfilename, "-"))
3740 logfile = fopen(config.logfilename, "a");
3741 av_log_set_callback(http_av_log);
3744 build_file_streams();
3746 build_feed_streams();
3748 compute_bandwidth();
3751 signal(SIGPIPE, SIG_IGN);
3753 if (http_server() < 0) {
3754 http_log("Could not start server\n");