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 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2258 c->cur_frame_bytes = len;
2259 c->buffer_ptr = c->pb_buffer;
2260 c->buffer_end = c->pb_buffer + len;
2262 codec->frame_number++;
2264 av_free_packet(&pkt);
2268 av_free_packet(&pkt);
2273 case HTTPSTATE_SEND_DATA_TRAILER:
2274 /* last packet test ? */
2275 if (c->last_packet_sent || c->is_packetized)
2278 /* prepare header */
2279 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2280 /* XXX: potential leak */
2283 c->fmt_ctx.pb->seekable = 0;
2284 av_write_trailer(ctx);
2285 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2286 c->buffer_ptr = c->pb_buffer;
2287 c->buffer_end = c->pb_buffer + len;
2289 c->last_packet_sent = 1;
2295 /* should convert the format at the same time */
2296 /* send data starting at c->buffer_ptr to the output connection
2297 * (either UDP or TCP) */
2298 static int http_send_data(HTTPContext *c)
2303 if (c->buffer_ptr >= c->buffer_end) {
2304 ret = http_prepare_data(c);
2308 /* state change requested */
2311 if (c->is_packetized) {
2312 /* RTP data output */
2313 len = c->buffer_end - c->buffer_ptr;
2315 /* fail safe - should never happen */
2317 c->buffer_ptr = c->buffer_end;
2320 len = (c->buffer_ptr[0] << 24) |
2321 (c->buffer_ptr[1] << 16) |
2322 (c->buffer_ptr[2] << 8) |
2324 if (len > (c->buffer_end - c->buffer_ptr))
2326 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2327 /* nothing to send yet: we can wait */
2331 c->data_count += len;
2332 update_datarate(&c->datarate, c->data_count);
2334 c->stream->bytes_served += len;
2336 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2337 /* RTP packets are sent inside the RTSP TCP connection */
2339 int interleaved_index, size;
2341 HTTPContext *rtsp_c;
2344 /* if no RTSP connection left, error */
2347 /* if already sending something, then wait. */
2348 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2350 if (avio_open_dyn_buf(&pb) < 0)
2352 interleaved_index = c->packet_stream_index * 2;
2353 /* RTCP packets are sent at odd indexes */
2354 if (c->buffer_ptr[1] == 200)
2355 interleaved_index++;
2356 /* write RTSP TCP header */
2358 header[1] = interleaved_index;
2359 header[2] = len >> 8;
2361 avio_write(pb, header, 4);
2362 /* write RTP packet data */
2364 avio_write(pb, c->buffer_ptr, len);
2365 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2366 /* prepare asynchronous TCP sending */
2367 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2368 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2369 c->buffer_ptr += len;
2371 /* send everything we can NOW */
2372 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2373 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2375 rtsp_c->packet_buffer_ptr += len;
2376 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2377 /* if we could not send all the data, we will
2378 send it later, so a new state is needed to
2379 "lock" the RTSP TCP connection */
2380 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2383 /* all data has been sent */
2384 av_freep(&c->packet_buffer);
2386 /* send RTP packet directly in UDP */
2388 ffurl_write(c->rtp_handles[c->packet_stream_index],
2389 c->buffer_ptr, len);
2390 c->buffer_ptr += len;
2391 /* here we continue as we can send several packets per 10 ms slot */
2394 /* TCP data output */
2395 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2397 if (ff_neterrno() != AVERROR(EAGAIN) &&
2398 ff_neterrno() != AVERROR(EINTR))
2399 /* error : close connection */
2404 c->buffer_ptr += len;
2406 c->data_count += len;
2407 update_datarate(&c->datarate, c->data_count);
2409 c->stream->bytes_served += len;
2417 static int http_start_receive_data(HTTPContext *c)
2422 if (c->stream->feed_opened) {
2423 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2424 return AVERROR(EINVAL);
2427 /* Don't permit writing to this one */
2428 if (c->stream->readonly) {
2429 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2430 return AVERROR(EINVAL);
2434 fd = open(c->stream->feed_filename, O_RDWR);
2436 ret = AVERROR(errno);
2437 http_log("Could not open feed file '%s': %s\n",
2438 c->stream->feed_filename, strerror(errno));
2443 if (c->stream->truncate) {
2444 /* truncate feed file */
2445 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2446 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2447 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2448 ret = AVERROR(errno);
2449 http_log("Error truncating feed file '%s': %s\n",
2450 c->stream->feed_filename, strerror(errno));
2454 ret = ffm_read_write_index(fd);
2456 http_log("Error reading write index from feed file '%s': %s\n",
2457 c->stream->feed_filename, strerror(errno));
2460 c->stream->feed_write_index = ret;
2464 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2465 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2466 lseek(fd, 0, SEEK_SET);
2468 /* init buffer input */
2469 c->buffer_ptr = c->buffer;
2470 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2471 c->stream->feed_opened = 1;
2472 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2476 static int http_receive_data(HTTPContext *c)
2479 int len, loop_run = 0;
2481 while (c->chunked_encoding && !c->chunk_size &&
2482 c->buffer_end > c->buffer_ptr) {
2483 /* read chunk header, if present */
2484 len = recv(c->fd, c->buffer_ptr, 1, 0);
2487 if (ff_neterrno() != AVERROR(EAGAIN) &&
2488 ff_neterrno() != AVERROR(EINTR))
2489 /* error : close connection */
2492 } else if (len == 0) {
2493 /* end of connection : close it */
2495 } else if (c->buffer_ptr - c->buffer >= 2 &&
2496 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2497 c->chunk_size = strtol(c->buffer, 0, 16);
2498 if (c->chunk_size == 0) // end of stream
2500 c->buffer_ptr = c->buffer;
2502 } else if (++loop_run > 10) {
2503 /* no chunk header, abort */
2510 if (c->buffer_end > c->buffer_ptr) {
2511 len = recv(c->fd, c->buffer_ptr,
2512 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2514 if (ff_neterrno() != AVERROR(EAGAIN) &&
2515 ff_neterrno() != AVERROR(EINTR))
2516 /* error : close connection */
2518 } else if (len == 0)
2519 /* end of connection : close it */
2522 c->chunk_size -= len;
2523 c->buffer_ptr += len;
2524 c->data_count += len;
2525 update_datarate(&c->datarate, c->data_count);
2529 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2530 if (c->buffer[0] != 'f' ||
2531 c->buffer[1] != 'm') {
2532 http_log("Feed stream has become desynchronized -- disconnecting\n");
2537 if (c->buffer_ptr >= c->buffer_end) {
2538 FFServerStream *feed = c->stream;
2539 /* a packet has been received : write it in the store, except
2541 if (c->data_count > FFM_PACKET_SIZE) {
2542 /* XXX: use llseek or url_seek
2543 * XXX: Should probably fail? */
2544 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2545 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2547 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2548 http_log("Error writing to feed file: %s\n", strerror(errno));
2552 feed->feed_write_index += FFM_PACKET_SIZE;
2553 /* update file size */
2554 if (feed->feed_write_index > c->stream->feed_size)
2555 feed->feed_size = feed->feed_write_index;
2557 /* handle wrap around if max file size reached */
2558 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2559 feed->feed_write_index = FFM_PACKET_SIZE;
2562 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2563 http_log("Error writing index to feed file: %s\n", strerror(errno));
2567 /* wake up any waiting connections */
2568 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2569 if (c1->state == HTTPSTATE_WAIT_FEED &&
2570 c1->stream->feed == c->stream->feed)
2571 c1->state = HTTPSTATE_SEND_DATA;
2574 /* We have a header in our hands that contains useful data */
2575 AVFormatContext *s = avformat_alloc_context();
2577 AVInputFormat *fmt_in;
2583 /* use feed output format name to find corresponding input format */
2584 fmt_in = av_find_input_format(feed->fmt->name);
2588 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2589 0, NULL, NULL, NULL, NULL);
2593 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2598 /* Now we have the actual streams */
2599 if (s->nb_streams != feed->nb_streams) {
2600 avformat_close_input(&s);
2602 http_log("Feed '%s' stream number does not match registered feed\n",
2603 c->stream->feed_filename);
2607 for (i = 0; i < s->nb_streams; i++) {
2608 AVStream *fst = feed->streams[i];
2609 AVStream *st = s->streams[i];
2610 avcodec_copy_context(fst->codec, st->codec);
2613 avformat_close_input(&s);
2616 c->buffer_ptr = c->buffer;
2621 c->stream->feed_opened = 0;
2623 /* wake up any waiting connections to stop waiting for feed */
2624 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2625 if (c1->state == HTTPSTATE_WAIT_FEED &&
2626 c1->stream->feed == c->stream->feed)
2627 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2632 /********************************************************************/
2635 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2642 str = RTSP_STATUS_CODE2STRING(error_number);
2644 str = "Unknown Error";
2646 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2647 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2649 /* output GMT time */
2652 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2653 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2656 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2658 rtsp_reply_header(c, error_number);
2659 avio_printf(c->pb, "\r\n");
2662 static int rtsp_parse_request(HTTPContext *c)
2664 const char *p, *p1, *p2;
2670 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2672 c->buffer_ptr[0] = '\0';
2675 get_word(cmd, sizeof(cmd), &p);
2676 get_word(url, sizeof(url), &p);
2677 get_word(protocol, sizeof(protocol), &p);
2679 av_strlcpy(c->method, cmd, sizeof(c->method));
2680 av_strlcpy(c->url, url, sizeof(c->url));
2681 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2683 if (avio_open_dyn_buf(&c->pb) < 0) {
2684 /* XXX: cannot do more */
2685 c->pb = NULL; /* safety */
2689 /* check version name */
2690 if (strcmp(protocol, "RTSP/1.0")) {
2691 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2695 /* parse each header line */
2696 /* skip to next line */
2697 while (*p != '\n' && *p != '\0')
2701 while (*p != '\0') {
2702 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2706 if (p2 > p && p2[-1] == '\r')
2708 /* skip empty line */
2712 if (len > sizeof(line) - 1)
2713 len = sizeof(line) - 1;
2714 memcpy(line, p, len);
2716 ff_rtsp_parse_line(header, line, NULL, NULL);
2720 /* handle sequence number */
2721 c->seq = header->seq;
2723 if (!strcmp(cmd, "DESCRIBE"))
2724 rtsp_cmd_describe(c, url);
2725 else if (!strcmp(cmd, "OPTIONS"))
2726 rtsp_cmd_options(c, url);
2727 else if (!strcmp(cmd, "SETUP"))
2728 rtsp_cmd_setup(c, url, header);
2729 else if (!strcmp(cmd, "PLAY"))
2730 rtsp_cmd_play(c, url, header);
2731 else if (!strcmp(cmd, "PAUSE"))
2732 rtsp_cmd_interrupt(c, url, header, 1);
2733 else if (!strcmp(cmd, "TEARDOWN"))
2734 rtsp_cmd_interrupt(c, url, header, 0);
2736 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2739 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2740 c->pb = NULL; /* safety */
2742 /* XXX: cannot do more */
2745 c->buffer_ptr = c->pb_buffer;
2746 c->buffer_end = c->pb_buffer + len;
2747 c->state = RTSPSTATE_SEND_REPLY;
2751 static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer,
2752 struct in_addr my_ip)
2754 AVFormatContext *avc;
2755 AVStream *avs = NULL;
2756 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2757 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2762 avc = avformat_alloc_context();
2763 if (!avc || !rtp_format) {
2766 avc->oformat = rtp_format;
2767 av_dict_set(&avc->metadata, "title",
2768 entry ? entry->value : "No Title", 0);
2769 avc->nb_streams = stream->nb_streams;
2770 if (stream->is_multicast) {
2771 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2772 inet_ntoa(stream->multicast_ip),
2773 stream->multicast_port, stream->multicast_ttl);
2775 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2778 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2779 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2781 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2782 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2785 for(i = 0; i < stream->nb_streams; i++) {
2786 avc->streams[i] = &avs[i];
2787 avc->streams[i]->codec = stream->streams[i]->codec;
2789 *pbuffer = av_mallocz(2048);
2790 av_sdp_create(&avc, 1, *pbuffer, 2048);
2793 av_freep(&avc->streams);
2794 av_dict_free(&avc->metadata);
2798 return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
2801 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2803 // rtsp_reply_header(c, RTSP_STATUS_OK);
2804 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2805 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2806 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2807 avio_printf(c->pb, "\r\n");
2810 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2812 FFServerStream *stream;
2818 struct sockaddr_in my_addr;
2820 /* find which URL is asked */
2821 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2826 for(stream = config.first_stream; stream; stream = stream->next) {
2827 if (!stream->is_feed &&
2828 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2829 !strcmp(path, stream->filename)) {
2833 /* no stream found */
2834 rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
2838 /* prepare the media description in SDP format */
2840 /* get the host IP */
2841 len = sizeof(my_addr);
2842 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
2843 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
2844 if (content_length < 0) {
2845 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2848 rtsp_reply_header(c, RTSP_STATUS_OK);
2849 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
2850 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
2851 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
2852 avio_printf(c->pb, "\r\n");
2853 avio_write(c->pb, content, content_length);
2857 static HTTPContext *find_rtp_session(const char *session_id)
2861 if (session_id[0] == '\0')
2864 for(c = first_http_ctx; c; c = c->next) {
2865 if (!strcmp(c->session_id, session_id))
2871 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
2873 RTSPTransportField *th;
2876 for(i=0;i<h->nb_transports;i++) {
2877 th = &h->transports[i];
2878 if (th->lower_transport == lower_transport)
2884 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
2885 RTSPMessageHeader *h)
2887 FFServerStream *stream;
2888 int stream_index, rtp_port, rtcp_port;
2893 RTSPTransportField *th;
2894 struct sockaddr_in dest_addr;
2895 RTSPActionServerSetup setup;
2897 /* find which URL is asked */
2898 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2903 /* now check each stream */
2904 for(stream = config.first_stream; stream; stream = stream->next) {
2905 if (!stream->is_feed &&
2906 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
2907 /* accept aggregate filenames only if single stream */
2908 if (!strcmp(path, stream->filename)) {
2909 if (stream->nb_streams != 1) {
2910 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
2917 for(stream_index = 0; stream_index < stream->nb_streams;
2919 snprintf(buf, sizeof(buf), "%s/streamid=%d",
2920 stream->filename, stream_index);
2921 if (!strcmp(path, buf))
2926 /* no stream found */
2927 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
2931 /* generate session id if needed */
2932 if (h->session_id[0] == '\0') {
2933 unsigned random0 = av_lfg_get(&random_state);
2934 unsigned random1 = av_lfg_get(&random_state);
2935 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
2939 /* find RTP session, and create it if none found */
2940 rtp_c = find_rtp_session(h->session_id);
2942 /* always prefer UDP */
2943 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
2945 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
2947 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2952 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
2953 th->lower_transport);
2955 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
2959 /* open input stream */
2960 if (open_input_stream(rtp_c, "") < 0) {
2961 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
2966 /* test if stream is OK (test needed because several SETUP needs
2967 to be done for a given file) */
2968 if (rtp_c->stream != stream) {
2969 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
2973 /* test if stream is already set up */
2974 if (rtp_c->rtp_ctx[stream_index]) {
2975 rtsp_reply_error(c, RTSP_STATUS_STATE);
2979 /* check transport */
2980 th = find_transport(h, rtp_c->rtp_protocol);
2981 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
2982 th->client_port_min <= 0)) {
2983 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2987 /* setup default options */
2988 setup.transport_option[0] = '\0';
2989 dest_addr = rtp_c->from_addr;
2990 dest_addr.sin_port = htons(th->client_port_min);
2993 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
2994 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
2998 /* now everything is OK, so we can send the connection parameters */
2999 rtsp_reply_header(c, RTSP_STATUS_OK);
3001 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3003 switch(rtp_c->rtp_protocol) {
3004 case RTSP_LOWER_TRANSPORT_UDP:
3005 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3006 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3007 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3008 "client_port=%d-%d;server_port=%d-%d",
3009 th->client_port_min, th->client_port_max,
3010 rtp_port, rtcp_port);
3012 case RTSP_LOWER_TRANSPORT_TCP:
3013 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3014 stream_index * 2, stream_index * 2 + 1);
3019 if (setup.transport_option[0] != '\0')
3020 avio_printf(c->pb, ";%s", setup.transport_option);
3021 avio_printf(c->pb, "\r\n");
3024 avio_printf(c->pb, "\r\n");
3028 /* find an RTP connection by using the session ID. Check consistency
3030 static HTTPContext *find_rtp_session_with_url(const char *url,
3031 const char *session_id)
3039 rtp_c = find_rtp_session(session_id);
3043 /* find which URL is asked */
3044 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3048 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3049 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3050 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3051 rtp_c->stream->filename, s);
3052 if(!strncmp(path, buf, sizeof(buf))) {
3053 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3058 if (len > 0 && path[len - 1] == '/' &&
3059 !strncmp(path, rtp_c->stream->filename, len - 1))
3064 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3068 rtp_c = find_rtp_session_with_url(url, h->session_id);
3070 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3074 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3075 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3076 rtp_c->state != HTTPSTATE_READY) {
3077 rtsp_reply_error(c, RTSP_STATUS_STATE);
3081 rtp_c->state = HTTPSTATE_SEND_DATA;
3083 /* now everything is OK, so we can send the connection parameters */
3084 rtsp_reply_header(c, RTSP_STATUS_OK);
3086 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3087 avio_printf(c->pb, "\r\n");
3090 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3094 rtp_c = find_rtp_session_with_url(url, h->session_id);
3096 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3101 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3102 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3103 rtsp_reply_error(c, RTSP_STATUS_STATE);
3106 rtp_c->state = HTTPSTATE_READY;
3107 rtp_c->first_pts = AV_NOPTS_VALUE;
3110 /* now everything is OK, so we can send the connection parameters */
3111 rtsp_reply_header(c, RTSP_STATUS_OK);
3113 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3114 avio_printf(c->pb, "\r\n");
3117 close_connection(rtp_c);
3120 /********************************************************************/
3123 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3124 FFServerStream *stream, const char *session_id,
3125 enum RTSPLowerTransport rtp_protocol)
3127 HTTPContext *c = NULL;
3128 const char *proto_str;
3130 /* XXX: should output a warning page when coming
3131 close to the connection limit */
3132 if (nb_connections >= config.nb_max_connections)
3135 /* add a new connection */
3136 c = av_mallocz(sizeof(HTTPContext));
3141 c->poll_entry = NULL;
3142 c->from_addr = *from_addr;
3143 c->buffer_size = IOBUFFER_INIT_SIZE;
3144 c->buffer = av_malloc(c->buffer_size);
3149 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3150 c->state = HTTPSTATE_READY;
3151 c->is_packetized = 1;
3152 c->rtp_protocol = rtp_protocol;
3154 /* protocol is shown in statistics */
3155 switch(c->rtp_protocol) {
3156 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3157 proto_str = "MCAST";
3159 case RTSP_LOWER_TRANSPORT_UDP:
3162 case RTSP_LOWER_TRANSPORT_TCP:
3169 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3170 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3172 current_bandwidth += stream->bandwidth;
3174 c->next = first_http_ctx;
3180 av_freep(&c->buffer);
3186 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3187 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3189 static int rtp_new_av_stream(HTTPContext *c,
3190 int stream_index, struct sockaddr_in *dest_addr,
3191 HTTPContext *rtsp_c)
3193 AVFormatContext *ctx;
3196 URLContext *h = NULL;
3198 int max_packet_size;
3200 /* now we can open the relevant output stream */
3201 ctx = avformat_alloc_context();
3204 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3206 st = av_mallocz(sizeof(AVStream));
3209 ctx->nb_streams = 1;
3210 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3213 ctx->streams[0] = st;
3215 if (!c->stream->feed ||
3216 c->stream->feed == c->stream)
3217 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3220 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3222 st->priv_data = NULL;
3224 /* build destination RTP address */
3225 ipaddr = inet_ntoa(dest_addr->sin_addr);
3227 switch(c->rtp_protocol) {
3228 case RTSP_LOWER_TRANSPORT_UDP:
3229 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3232 /* XXX: also pass as parameter to function ? */
3233 if (c->stream->is_multicast) {
3235 ttl = c->stream->multicast_ttl;
3238 snprintf(ctx->filename, sizeof(ctx->filename),
3239 "rtp://%s:%d?multicast=1&ttl=%d",
3240 ipaddr, ntohs(dest_addr->sin_port), ttl);
3242 snprintf(ctx->filename, sizeof(ctx->filename),
3243 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3246 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3248 c->rtp_handles[stream_index] = h;
3249 max_packet_size = h->max_packet_size;
3251 case RTSP_LOWER_TRANSPORT_TCP:
3254 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3260 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3261 ipaddr, ntohs(dest_addr->sin_port),
3262 c->stream->filename, stream_index, c->protocol);
3264 /* normally, no packets should be output here, but the packet size may
3266 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3267 /* XXX: close stream */
3270 if (avformat_write_header(ctx, NULL) < 0) {
3278 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3281 c->rtp_ctx[stream_index] = ctx;
3285 /********************************************************************/
3286 /* ffserver initialization */
3288 static AVStream *add_av_stream1(FFServerStream *stream, AVCodecContext *codec, int copy)
3292 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3295 fst = av_mallocz(sizeof(AVStream));
3299 fst->codec = avcodec_alloc_context3(NULL);
3300 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3301 if (codec->extradata_size) {
3302 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3303 memcpy(fst->codec->extradata, codec->extradata,
3304 codec->extradata_size);
3307 /* live streams must use the actual feed's codec since it may be
3308 * updated later to carry extradata needed by them.
3312 fst->priv_data = av_mallocz(sizeof(FeedData));
3313 fst->index = stream->nb_streams;
3314 avpriv_set_pts_info(fst, 33, 1, 90000);
3315 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3316 stream->streams[stream->nb_streams++] = fst;
3320 /* return the stream number in the feed */
3321 static int add_av_stream(FFServerStream *feed, AVStream *st)
3324 AVCodecContext *av, *av1;
3328 for(i=0;i<feed->nb_streams;i++) {
3329 av1 = feed->streams[i]->codec;
3330 if (av1->codec_id == av->codec_id &&
3331 av1->codec_type == av->codec_type &&
3332 av1->bit_rate == av->bit_rate) {
3334 switch(av->codec_type) {
3335 case AVMEDIA_TYPE_AUDIO:
3336 if (av1->channels == av->channels &&
3337 av1->sample_rate == av->sample_rate)
3340 case AVMEDIA_TYPE_VIDEO:
3341 if (av1->width == av->width &&
3342 av1->height == av->height &&
3343 av1->time_base.den == av->time_base.den &&
3344 av1->time_base.num == av->time_base.num &&
3345 av1->gop_size == av->gop_size)
3354 fst = add_av_stream1(feed, av, 0);
3357 if (av_stream_get_recommended_encoder_configuration(st))
3358 av_stream_set_recommended_encoder_configuration(fst,
3359 av_strdup(av_stream_get_recommended_encoder_configuration(st)));
3360 return feed->nb_streams - 1;
3363 static void remove_stream(FFServerStream *stream)
3365 FFServerStream **ps;
3366 ps = &config.first_stream;
3375 /* specific MPEG4 handling : we extract the raw parameters */
3376 static void extract_mpeg4_header(AVFormatContext *infile)
3378 int mpeg4_count, i, size;
3383 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3386 for(i=0;i<infile->nb_streams;i++) {
3387 st = infile->streams[i];
3388 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3389 st->codec->extradata_size == 0) {
3396 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3397 while (mpeg4_count > 0) {
3398 if (av_read_frame(infile, &pkt) < 0)
3400 st = infile->streams[pkt.stream_index];
3401 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3402 st->codec->extradata_size == 0) {
3403 av_freep(&st->codec->extradata);
3404 /* fill extradata with the header */
3405 /* XXX: we make hard suppositions here ! */
3407 while (p < pkt.data + pkt.size - 4) {
3408 /* stop when vop header is found */
3409 if (p[0] == 0x00 && p[1] == 0x00 &&
3410 p[2] == 0x01 && p[3] == 0xb6) {
3411 size = p - pkt.data;
3412 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3413 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3414 st->codec->extradata_size = size;
3415 memcpy(st->codec->extradata, pkt.data, size);
3422 av_free_packet(&pkt);
3426 /* compute the needed AVStream for each file */
3427 static void build_file_streams(void)
3429 FFServerStream *stream, *stream_next;
3432 /* gather all streams */
3433 for(stream = config.first_stream; stream; stream = stream_next) {
3434 AVFormatContext *infile = NULL;
3435 stream_next = stream->next;
3436 if (stream->stream_type == STREAM_TYPE_LIVE &&
3438 /* the stream comes from a file */
3439 /* try to open the file */
3441 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3442 /* specific case : if transport stream output to RTP,
3443 we use a raw transport stream reader */
3444 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3447 if (!stream->feed_filename[0]) {
3448 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3452 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3453 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3454 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3455 /* remove stream (no need to spend more time on it) */
3457 remove_stream(stream);
3459 /* find all the AVStreams inside and reference them in
3461 if (avformat_find_stream_info(infile, NULL) < 0) {
3462 http_log("Could not find codec parameters from '%s'\n",
3463 stream->feed_filename);
3464 avformat_close_input(&infile);
3467 extract_mpeg4_header(infile);
3469 for(i=0;i<infile->nb_streams;i++)
3470 add_av_stream1(stream, infile->streams[i]->codec, 1);
3472 avformat_close_input(&infile);
3478 /* compute the needed AVStream for each feed */
3479 static void build_feed_streams(void)
3481 FFServerStream *stream, *feed;
3484 /* gather all streams */
3485 for(stream = config.first_stream; stream; stream = stream->next) {
3486 feed = stream->feed;
3488 if (stream->is_feed) {
3489 for(i=0;i<stream->nb_streams;i++)
3490 stream->feed_streams[i] = i;
3492 /* we handle a stream coming from a feed */
3493 for(i=0;i<stream->nb_streams;i++)
3494 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3499 /* create feed files if needed */
3500 for(feed = config.first_feed; feed; feed = feed->next_feed) {
3503 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3504 /* See if it matches */
3505 AVFormatContext *s = NULL;
3508 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3509 /* set buffer size */
3510 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3511 /* Now see if it matches */
3512 if (s->nb_streams == feed->nb_streams) {
3514 for(i=0;i<s->nb_streams;i++) {
3516 sf = feed->streams[i];
3519 if (sf->index != ss->index ||
3521 http_log("Index & Id do not match for stream %d (%s)\n",
3522 i, feed->feed_filename);
3525 AVCodecContext *ccf, *ccs;
3529 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3531 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3532 http_log("Codecs do not match for stream %d\n", i);
3534 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3535 http_log("Codec bitrates do not match for stream %d\n", i);
3537 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3538 if (CHECK_CODEC(time_base.den) ||
3539 CHECK_CODEC(time_base.num) ||
3540 CHECK_CODEC(width) ||
3541 CHECK_CODEC(height)) {
3542 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3545 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3546 if (CHECK_CODEC(sample_rate) ||
3547 CHECK_CODEC(channels) ||
3548 CHECK_CODEC(frame_size)) {
3549 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3553 http_log("Unknown codec type\n");
3561 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3562 feed->feed_filename, s->nb_streams, feed->nb_streams);
3564 avformat_close_input(&s);
3566 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3567 feed->feed_filename);
3570 if (feed->readonly) {
3571 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3572 feed->feed_filename);
3575 unlink(feed->feed_filename);
3578 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3579 AVFormatContext *s = avformat_alloc_context();
3581 if (feed->readonly) {
3582 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3583 feed->feed_filename);
3587 /* only write the header of the ffm file */
3588 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3589 http_log("Could not open output feed file '%s'\n",
3590 feed->feed_filename);
3593 s->oformat = feed->fmt;
3594 s->nb_streams = feed->nb_streams;
3595 s->streams = feed->streams;
3596 if (avformat_write_header(s, NULL) < 0) {
3597 http_log("Container doesn't support the required parameters\n");
3600 /* XXX: need better API */
3601 av_freep(&s->priv_data);
3605 avformat_free_context(s);
3607 /* get feed size and write index */
3608 fd = open(feed->feed_filename, O_RDONLY);
3610 http_log("Could not open output feed file '%s'\n",
3611 feed->feed_filename);
3615 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3616 feed->feed_size = lseek(fd, 0, SEEK_END);
3617 /* ensure that we do not wrap before the end of file */
3618 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3619 feed->feed_max_size = feed->feed_size;
3625 /* compute the bandwidth used by each stream */
3626 static void compute_bandwidth(void)
3630 FFServerStream *stream;
3632 for(stream = config.first_stream; stream; stream = stream->next) {
3634 for(i=0;i<stream->nb_streams;i++) {
3635 AVStream *st = stream->streams[i];
3636 switch(st->codec->codec_type) {
3637 case AVMEDIA_TYPE_AUDIO:
3638 case AVMEDIA_TYPE_VIDEO:
3639 bandwidth += st->codec->bit_rate;
3645 stream->bandwidth = (bandwidth + 999) / 1000;
3649 static void handle_child_exit(int sig)
3654 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
3655 FFServerStream *feed;
3657 for (feed = config.first_feed; feed; feed = feed->next) {
3658 if (feed->pid == pid) {
3659 int uptime = time(0) - feed->pid_start;
3662 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
3665 /* Turn off any more restarts */
3666 feed->child_argv = 0;
3671 need_to_start_children = 1;
3674 static void opt_debug(void)
3677 snprintf(config.logfilename, sizeof(config.logfilename), "-");
3680 void show_help_default(const char *opt, const char *arg)
3682 printf("usage: ffserver [options]\n"
3683 "Hyper fast multi format Audio/Video streaming server\n");
3685 show_help_options(options, "Main options:", 0, 0, 0);
3688 static const OptionDef options[] = {
3689 #include "cmdutils_common_opts.h"
3690 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
3691 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
3692 { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
3696 int main(int argc, char **argv)
3698 struct sigaction sigact = { { 0 } };
3701 config.filename = av_strdup("/etc/ffserver.conf");
3703 parse_loglevel(argc, argv, options);
3705 avformat_network_init();
3707 show_banner(argc, argv, options);
3709 my_program_name = argv[0];
3711 parse_options(NULL, argc, argv, options, NULL);
3713 unsetenv("http_proxy"); /* Kill the http_proxy */
3715 av_lfg_init(&random_state, av_get_random_seed());
3717 sigact.sa_handler = handle_child_exit;
3718 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
3719 sigaction(SIGCHLD, &sigact, 0);
3721 if ((ret = ffserver_parse_ffconfig(config.filename, &config)) < 0) {
3722 fprintf(stderr, "Error reading configuration file '%s': %s\n",
3723 config.filename, av_err2str(ret));
3726 av_freep(&config.filename);
3728 /* open log file if needed */
3729 if (config.logfilename[0] != '\0') {
3730 if (!strcmp(config.logfilename, "-"))
3733 logfile = fopen(config.logfilename, "a");
3734 av_log_set_callback(http_av_log);
3737 build_file_streams();
3739 build_feed_streams();
3741 compute_bandwidth();
3744 signal(SIGPIPE, SIG_IGN);
3746 if (http_server() < 0) {
3747 http_log("Could not start server\n");