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/rtsp.h"
40 #include "libavformat/avio_internal.h"
41 #include "libavformat/internal.h"
42 #include "libavformat/url.h"
44 #include "libavutil/avassert.h"
45 #include "libavutil/avstring.h"
46 #include "libavutil/lfg.h"
47 #include "libavutil/dict.h"
48 #include "libavutil/intreadwrite.h"
49 #include "libavutil/mathematics.h"
50 #include "libavutil/random_seed.h"
51 #include "libavutil/parseutils.h"
52 #include "libavutil/opt.h"
53 #include "libavutil/time.h"
58 #include <sys/ioctl.h>
72 const char program_name[] = "ffserver";
73 const int program_birth_year = 2000;
75 static const OptionDef options[];
78 HTTPSTATE_WAIT_REQUEST,
79 HTTPSTATE_SEND_HEADER,
80 HTTPSTATE_SEND_DATA_HEADER,
81 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
82 HTTPSTATE_SEND_DATA_TRAILER,
83 HTTPSTATE_RECEIVE_DATA,
84 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
87 RTSPSTATE_WAIT_REQUEST,
89 RTSPSTATE_SEND_PACKET,
92 static const char *http_state[] = {
108 #define MAX_STREAMS 20
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 FFStream *stream;
158 /* -1 is invalid stream */
159 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
160 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
162 AVFormatContext fmt_ctx; /* instance of FFStream 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[MAX_STREAMS];
185 /* RTP/UDP specific */
186 URLContext *rtp_handles[MAX_STREAMS];
188 /* RTP/TCP specific */
189 struct HTTPContext *rtsp_c;
190 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
193 /* each generated stream is described here */
197 STREAM_TYPE_REDIRECT,
200 enum IPAddressAction {
205 typedef struct IPAddressACL {
206 struct IPAddressACL *next;
207 enum IPAddressAction action;
208 /* These are in host order */
209 struct in_addr first;
213 /* description of each stream of the ffserver.conf file */
214 typedef struct FFStream {
215 enum StreamType stream_type;
216 char filename[1024]; /* stream filename */
217 struct FFStream *feed; /* feed we are using (can be null if
219 AVDictionary *in_opts; /* input parameters */
220 AVInputFormat *ifmt; /* if non NULL, force input format */
223 char dynamic_acl[1024];
225 int prebuffer; /* Number of millseconds early to start */
226 int64_t max_time; /* Number of milliseconds to run */
228 AVStream *streams[MAX_STREAMS];
229 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
230 char feed_filename[1024]; /* file name of the feed storage, or
231 input file name for a stream */
236 pid_t pid; /* Of ffmpeg process */
237 time_t pid_start; /* Of ffmpeg process */
239 struct FFStream *next;
240 unsigned bandwidth; /* bandwidth, in kbits/s */
243 /* multicast specific */
245 struct in_addr multicast_ip;
246 int multicast_port; /* first port used for multicast */
248 int loop; /* if true, send the stream in loops (only meaningful if file) */
251 int feed_opened; /* true if someone is writing to the feed */
252 int is_feed; /* true if it is a feed */
253 int readonly; /* True if writing is prohibited to the file */
254 int truncate; /* True if feeder connection truncate the feed file */
256 int64_t bytes_served;
257 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
258 int64_t feed_write_index; /* current write position in feed (it wraps around) */
259 int64_t feed_size; /* current size of feed */
260 struct FFStream *next_feed;
263 typedef struct FeedData {
264 long long data_count;
265 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
268 static struct sockaddr_in my_http_addr;
269 static struct sockaddr_in my_rtsp_addr;
271 static char logfilename[1024];
272 static HTTPContext *first_http_ctx;
273 static FFStream *first_feed; /* contains only feeds */
274 static FFStream *first_stream; /* contains all streams, including feeds */
276 static void new_connection(int server_fd, int is_rtsp);
277 static void close_connection(HTTPContext *c);
280 static int handle_connection(HTTPContext *c);
281 static int http_parse_request(HTTPContext *c);
282 static int http_send_data(HTTPContext *c);
283 static void compute_status(HTTPContext *c);
284 static int open_input_stream(HTTPContext *c, const char *info);
285 static int http_start_receive_data(HTTPContext *c);
286 static int http_receive_data(HTTPContext *c);
289 static int rtsp_parse_request(HTTPContext *c);
290 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
291 static void rtsp_cmd_options(HTTPContext *c, const char *url);
292 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
293 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
294 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
295 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
298 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
299 struct in_addr my_ip);
302 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
303 FFStream *stream, const char *session_id,
304 enum RTSPLowerTransport rtp_protocol);
305 static int rtp_new_av_stream(HTTPContext *c,
306 int stream_index, struct sockaddr_in *dest_addr,
307 HTTPContext *rtsp_c);
309 static const char *my_program_name;
311 static const char *config_filename = "/etc/ffserver.conf";
313 static int ffserver_debug;
314 static int no_launch;
315 static int need_to_start_children;
317 /* maximum number of simultaneous HTTP connections */
318 static unsigned int nb_max_http_connections = 2000;
319 static unsigned int nb_max_connections = 5;
320 static unsigned int nb_connections;
322 static uint64_t max_bandwidth = 1000;
323 static uint64_t current_bandwidth;
325 static int64_t cur_time; // Making this global saves on passing it around everywhere
327 static AVLFG random_state;
329 static FILE *logfile = NULL;
331 static int64_t ffm_read_write_index(int fd)
335 if (lseek(fd, 8, SEEK_SET) < 0)
337 if (read(fd, buf, 8) != 8)
342 static int ffm_write_write_index(int fd, int64_t pos)
348 buf[i] = (pos >> (56 - i * 8)) & 0xff;
349 if (lseek(fd, 8, SEEK_SET) < 0)
351 if (write(fd, buf, 8) != 8)
356 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
359 FFMContext *ffm = s->priv_data;
360 ffm->write_index = pos;
361 ffm->file_size = file_size;
364 /* FIXME: make ffserver work with IPv6 */
365 /* resolve host with also IP address parsing */
366 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
369 if (!ff_inet_aton(hostname, sin_addr)) {
371 struct addrinfo *ai, *cur;
372 struct addrinfo hints = { 0 };
373 hints.ai_family = AF_INET;
374 if (getaddrinfo(hostname, NULL, &hints, &ai))
376 /* getaddrinfo returns a linked list of addrinfo structs.
377 * Even if we set ai_family = AF_INET above, make sure
378 * that the returned one actually is of the correct type. */
379 for (cur = ai; cur; cur = cur->ai_next) {
380 if (cur->ai_family == AF_INET) {
381 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
390 hp = gethostbyname(hostname);
393 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
399 static char *ctime1(char *buf2)
407 p = buf2 + strlen(p) - 1;
413 static void http_vlog(const char *fmt, va_list vargs)
415 static int print_prefix = 1;
420 fprintf(logfile, "%s ", buf);
422 print_prefix = strstr(fmt, "\n") != NULL;
423 vfprintf(logfile, fmt, vargs);
429 __attribute__ ((format (printf, 1, 2)))
431 static void http_log(const char *fmt, ...)
434 va_start(vargs, fmt);
435 http_vlog(fmt, vargs);
439 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
441 static int print_prefix = 1;
442 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
443 if (level > av_log_get_level())
445 if (print_prefix && avc)
446 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
447 print_prefix = strstr(fmt, "\n") != NULL;
448 http_vlog(fmt, vargs);
451 static void log_connection(HTTPContext *c)
456 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
457 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
458 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
461 static void update_datarate(DataRateData *drd, int64_t count)
463 if (!drd->time1 && !drd->count1) {
464 drd->time1 = drd->time2 = cur_time;
465 drd->count1 = drd->count2 = count;
466 } else if (cur_time - drd->time2 > 5000) {
467 drd->time1 = drd->time2;
468 drd->count1 = drd->count2;
469 drd->time2 = cur_time;
474 /* In bytes per second */
475 static int compute_datarate(DataRateData *drd, int64_t count)
477 if (cur_time == drd->time1)
480 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
484 static void start_children(FFStream *feed)
489 for (; feed; feed = feed->next) {
490 if (feed->child_argv && !feed->pid) {
491 feed->pid_start = time(0);
496 http_log("Unable to create children\n");
505 av_strlcpy(pathname, my_program_name, sizeof(pathname));
507 slash = strrchr(pathname, '/');
512 strcpy(slash, "ffmpeg");
514 http_log("Launch command line: ");
515 http_log("%s ", pathname);
516 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
517 http_log("%s ", feed->child_argv[i]);
520 for (i = 3; i < 256; i++)
523 if (!ffserver_debug) {
524 if (!freopen("/dev/null", "r", stdin))
525 http_log("failed to redirect STDIN to /dev/null\n;");
526 if (!freopen("/dev/null", "w", stdout))
527 http_log("failed to redirect STDOUT to /dev/null\n;");
528 if (!freopen("/dev/null", "w", stderr))
529 http_log("failed to redirect STDERR to /dev/null\n;");
532 signal(SIGPIPE, SIG_DFL);
534 execvp(pathname, feed->child_argv);
542 /* open a listening socket */
543 static int socket_open_listen(struct sockaddr_in *my_addr)
547 server_fd = socket(AF_INET,SOCK_STREAM,0);
554 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
556 my_addr->sin_family = AF_INET;
557 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
559 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
561 closesocket(server_fd);
565 if (listen (server_fd, 5) < 0) {
567 closesocket(server_fd);
570 ff_socket_nonblock(server_fd, 1);
575 /* start all multicast streams */
576 static void start_multicast(void)
581 struct sockaddr_in dest_addr = {0};
582 int default_port, stream_index;
585 for(stream = first_stream; stream != NULL; stream = stream->next) {
586 if (stream->is_multicast) {
587 unsigned random0 = av_lfg_get(&random_state);
588 unsigned random1 = av_lfg_get(&random_state);
589 /* open the RTP connection */
590 snprintf(session_id, sizeof(session_id), "%08x%08x",
593 /* choose a port if none given */
594 if (stream->multicast_port == 0) {
595 stream->multicast_port = default_port;
599 dest_addr.sin_family = AF_INET;
600 dest_addr.sin_addr = stream->multicast_ip;
601 dest_addr.sin_port = htons(stream->multicast_port);
603 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
604 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
608 if (open_input_stream(rtp_c, "") < 0) {
609 http_log("Could not open input stream for stream '%s'\n",
614 /* open each RTP stream */
615 for(stream_index = 0; stream_index < stream->nb_streams;
617 dest_addr.sin_port = htons(stream->multicast_port +
619 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
620 http_log("Could not open output stream '%s/streamid=%d'\n",
621 stream->filename, stream_index);
626 /* change state to send data */
627 rtp_c->state = HTTPSTATE_SEND_DATA;
632 /* main loop of the http server */
633 static int http_server(void)
635 int server_fd = 0, rtsp_server_fd = 0;
636 int ret, delay, delay1;
637 struct pollfd *poll_table, *poll_entry;
638 HTTPContext *c, *c_next;
640 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
641 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
645 if (my_http_addr.sin_port) {
646 server_fd = socket_open_listen(&my_http_addr);
651 if (my_rtsp_addr.sin_port) {
652 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
653 if (rtsp_server_fd < 0)
657 if (!rtsp_server_fd && !server_fd) {
658 http_log("HTTP and RTSP disabled.\n");
662 http_log("FFserver started.\n");
664 start_children(first_feed);
669 poll_entry = poll_table;
671 poll_entry->fd = server_fd;
672 poll_entry->events = POLLIN;
675 if (rtsp_server_fd) {
676 poll_entry->fd = rtsp_server_fd;
677 poll_entry->events = POLLIN;
681 /* wait for events on each HTTP handle */
688 case HTTPSTATE_SEND_HEADER:
689 case RTSPSTATE_SEND_REPLY:
690 case RTSPSTATE_SEND_PACKET:
691 c->poll_entry = poll_entry;
693 poll_entry->events = POLLOUT;
696 case HTTPSTATE_SEND_DATA_HEADER:
697 case HTTPSTATE_SEND_DATA:
698 case HTTPSTATE_SEND_DATA_TRAILER:
699 if (!c->is_packetized) {
700 /* for TCP, we output as much as we can (may need to put a limit) */
701 c->poll_entry = poll_entry;
703 poll_entry->events = POLLOUT;
706 /* when ffserver is doing the timing, we work by
707 looking at which packet need to be sent every
709 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
714 case HTTPSTATE_WAIT_REQUEST:
715 case HTTPSTATE_RECEIVE_DATA:
716 case HTTPSTATE_WAIT_FEED:
717 case RTSPSTATE_WAIT_REQUEST:
718 /* need to catch errors */
719 c->poll_entry = poll_entry;
721 poll_entry->events = POLLIN;/* Maybe this will work */
725 c->poll_entry = NULL;
731 /* wait for an event on one connection. We poll at least every
732 second to handle timeouts */
734 ret = poll(poll_table, poll_entry - poll_table, delay);
735 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
736 ff_neterrno() != AVERROR(EINTR))
740 cur_time = av_gettime() / 1000;
742 if (need_to_start_children) {
743 need_to_start_children = 0;
744 start_children(first_feed);
747 /* now handle the events */
748 for(c = first_http_ctx; c != NULL; c = c_next) {
750 if (handle_connection(c) < 0) {
751 /* close and free the connection */
757 poll_entry = poll_table;
759 /* new HTTP connection request ? */
760 if (poll_entry->revents & POLLIN)
761 new_connection(server_fd, 0);
764 if (rtsp_server_fd) {
765 /* new RTSP connection request ? */
766 if (poll_entry->revents & POLLIN)
767 new_connection(rtsp_server_fd, 1);
772 /* start waiting for a new HTTP/RTSP request */
773 static void start_wait_request(HTTPContext *c, int is_rtsp)
775 c->buffer_ptr = c->buffer;
776 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
779 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
780 c->state = RTSPSTATE_WAIT_REQUEST;
782 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
783 c->state = HTTPSTATE_WAIT_REQUEST;
787 static void http_send_too_busy_reply(int fd)
790 int len = snprintf(buffer, sizeof(buffer),
791 "HTTP/1.0 503 Server too busy\r\n"
792 "Content-type: text/html\r\n"
794 "<html><head><title>Too busy</title></head><body>\r\n"
795 "<p>The server is too busy to serve your request at this time.</p>\r\n"
796 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
797 "</body></html>\r\n",
798 nb_connections, nb_max_connections);
799 av_assert0(len < sizeof(buffer));
800 send(fd, buffer, len, 0);
804 static void new_connection(int server_fd, int is_rtsp)
806 struct sockaddr_in from_addr;
809 HTTPContext *c = NULL;
811 len = sizeof(from_addr);
812 fd = accept(server_fd, (struct sockaddr *)&from_addr,
815 http_log("error during accept %s\n", strerror(errno));
818 ff_socket_nonblock(fd, 1);
820 if (nb_connections >= nb_max_connections) {
821 http_send_too_busy_reply(fd);
825 /* add a new connection */
826 c = av_mallocz(sizeof(HTTPContext));
831 c->poll_entry = NULL;
832 c->from_addr = from_addr;
833 c->buffer_size = IOBUFFER_INIT_SIZE;
834 c->buffer = av_malloc(c->buffer_size);
838 c->next = first_http_ctx;
842 start_wait_request(c, is_rtsp);
854 static void close_connection(HTTPContext *c)
856 HTTPContext **cp, *c1;
858 AVFormatContext *ctx;
862 /* remove connection from list */
863 cp = &first_http_ctx;
864 while ((*cp) != NULL) {
872 /* remove references, if any (XXX: do it faster) */
873 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
878 /* remove connection associated resources */
882 /* close each frame parser */
883 for(i=0;i<c->fmt_in->nb_streams;i++) {
884 st = c->fmt_in->streams[i];
885 if (st->codec->codec)
886 avcodec_close(st->codec);
888 avformat_close_input(&c->fmt_in);
891 /* free RTP output streams if any */
894 nb_streams = c->stream->nb_streams;
896 for(i=0;i<nb_streams;i++) {
899 av_write_trailer(ctx);
900 av_dict_free(&ctx->metadata);
901 av_free(ctx->streams[0]);
904 h = c->rtp_handles[i];
911 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
914 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
915 av_write_trailer(ctx);
916 av_freep(&c->pb_buffer);
917 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
922 for(i=0; i<ctx->nb_streams; i++)
923 av_free(ctx->streams[i]);
924 av_freep(&ctx->streams);
925 av_freep(&ctx->priv_data);
927 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
928 current_bandwidth -= c->stream->bandwidth;
930 /* signal that there is no feed if we are the feeder socket */
931 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
932 c->stream->feed_opened = 0;
936 av_freep(&c->pb_buffer);
937 av_freep(&c->packet_buffer);
943 static int handle_connection(HTTPContext *c)
948 case HTTPSTATE_WAIT_REQUEST:
949 case RTSPSTATE_WAIT_REQUEST:
951 if ((c->timeout - cur_time) < 0)
953 if (c->poll_entry->revents & (POLLERR | POLLHUP))
956 /* no need to read if no events */
957 if (!(c->poll_entry->revents & POLLIN))
961 len = recv(c->fd, c->buffer_ptr, 1, 0);
963 if (ff_neterrno() != AVERROR(EAGAIN) &&
964 ff_neterrno() != AVERROR(EINTR))
966 } else if (len == 0) {
969 /* search for end of request. */
971 c->buffer_ptr += len;
973 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
974 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
975 /* request found : parse it and reply */
976 if (c->state == HTTPSTATE_WAIT_REQUEST) {
977 ret = http_parse_request(c);
979 ret = rtsp_parse_request(c);
983 } else if (ptr >= c->buffer_end) {
984 /* request too long: cannot do anything */
986 } else goto read_loop;
990 case HTTPSTATE_SEND_HEADER:
991 if (c->poll_entry->revents & (POLLERR | POLLHUP))
994 /* no need to write if no events */
995 if (!(c->poll_entry->revents & POLLOUT))
997 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
999 if (ff_neterrno() != AVERROR(EAGAIN) &&
1000 ff_neterrno() != AVERROR(EINTR)) {
1001 /* error : close connection */
1002 av_freep(&c->pb_buffer);
1006 c->buffer_ptr += len;
1008 c->stream->bytes_served += len;
1009 c->data_count += len;
1010 if (c->buffer_ptr >= c->buffer_end) {
1011 av_freep(&c->pb_buffer);
1012 /* if error, exit */
1015 /* all the buffer was sent : synchronize to the incoming stream */
1016 c->state = HTTPSTATE_SEND_DATA_HEADER;
1017 c->buffer_ptr = c->buffer_end = c->buffer;
1022 case HTTPSTATE_SEND_DATA:
1023 case HTTPSTATE_SEND_DATA_HEADER:
1024 case HTTPSTATE_SEND_DATA_TRAILER:
1025 /* for packetized output, we consider we can always write (the
1026 input streams sets the speed). It may be better to verify
1027 that we do not rely too much on the kernel queues */
1028 if (!c->is_packetized) {
1029 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1032 /* no need to read if no events */
1033 if (!(c->poll_entry->revents & POLLOUT))
1036 if (http_send_data(c) < 0)
1038 /* close connection if trailer sent */
1039 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1042 case HTTPSTATE_RECEIVE_DATA:
1043 /* no need to read if no events */
1044 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1046 if (!(c->poll_entry->revents & POLLIN))
1048 if (http_receive_data(c) < 0)
1051 case HTTPSTATE_WAIT_FEED:
1052 /* no need to read if no events */
1053 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1056 /* nothing to do, we'll be waken up by incoming feed packets */
1059 case RTSPSTATE_SEND_REPLY:
1060 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1061 av_freep(&c->pb_buffer);
1064 /* no need to write if no events */
1065 if (!(c->poll_entry->revents & POLLOUT))
1067 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1069 if (ff_neterrno() != AVERROR(EAGAIN) &&
1070 ff_neterrno() != AVERROR(EINTR)) {
1071 /* error : close connection */
1072 av_freep(&c->pb_buffer);
1076 c->buffer_ptr += len;
1077 c->data_count += len;
1078 if (c->buffer_ptr >= c->buffer_end) {
1079 /* all the buffer was sent : wait for a new request */
1080 av_freep(&c->pb_buffer);
1081 start_wait_request(c, 1);
1085 case RTSPSTATE_SEND_PACKET:
1086 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1087 av_freep(&c->packet_buffer);
1090 /* no need to write if no events */
1091 if (!(c->poll_entry->revents & POLLOUT))
1093 len = send(c->fd, c->packet_buffer_ptr,
1094 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1096 if (ff_neterrno() != AVERROR(EAGAIN) &&
1097 ff_neterrno() != AVERROR(EINTR)) {
1098 /* error : close connection */
1099 av_freep(&c->packet_buffer);
1103 c->packet_buffer_ptr += len;
1104 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1105 /* all the buffer was sent : wait for a new request */
1106 av_freep(&c->packet_buffer);
1107 c->state = RTSPSTATE_WAIT_REQUEST;
1111 case HTTPSTATE_READY:
1120 static int extract_rates(char *rates, int ratelen, const char *request)
1124 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1125 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1126 const char *q = p + 7;
1128 while (*q && *q != '\n' && isspace(*q))
1131 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1137 memset(rates, 0xff, ratelen);
1140 while (*q && *q != '\n' && *q != ':')
1143 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1147 if (stream_no < ratelen && stream_no >= 0)
1148 rates[stream_no] = rate_no;
1150 while (*q && *q != '\n' && !isspace(*q))
1157 p = strchr(p, '\n');
1167 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1170 int best_bitrate = 100000000;
1173 for (i = 0; i < feed->nb_streams; i++) {
1174 AVCodecContext *feed_codec = feed->streams[i]->codec;
1176 if (feed_codec->codec_id != codec->codec_id ||
1177 feed_codec->sample_rate != codec->sample_rate ||
1178 feed_codec->width != codec->width ||
1179 feed_codec->height != codec->height)
1182 /* Potential stream */
1184 /* We want the fastest stream less than bit_rate, or the slowest
1185 * faster than bit_rate
1188 if (feed_codec->bit_rate <= bit_rate) {
1189 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1190 best_bitrate = feed_codec->bit_rate;
1194 if (feed_codec->bit_rate < best_bitrate) {
1195 best_bitrate = feed_codec->bit_rate;
1204 static int modify_current_stream(HTTPContext *c, char *rates)
1207 FFStream *req = c->stream;
1208 int action_required = 0;
1210 /* Not much we can do for a feed */
1214 for (i = 0; i < req->nb_streams; i++) {
1215 AVCodecContext *codec = req->streams[i]->codec;
1219 c->switch_feed_streams[i] = req->feed_streams[i];
1222 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1225 /* Wants off or slow */
1226 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1228 /* This doesn't work well when it turns off the only stream! */
1229 c->switch_feed_streams[i] = -2;
1230 c->feed_streams[i] = -2;
1235 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1236 action_required = 1;
1239 return action_required;
1242 /* XXX: factorize in utils.c ? */
1243 /* XXX: take care with different space meaning */
1244 static void skip_spaces(const char **pp)
1248 while (*p == ' ' || *p == '\t')
1253 static void get_word(char *buf, int buf_size, const char **pp)
1261 while (!isspace(*p) && *p != '\0') {
1262 if ((q - buf) < buf_size - 1)
1271 static void get_arg(char *buf, int buf_size, const char **pp)
1278 while (isspace(*p)) p++;
1281 if (*p == '\"' || *p == '\'')
1293 if ((q - buf) < buf_size - 1)
1298 if (quote && *p == quote)
1303 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1304 const char *p, const char *filename, int line_num)
1310 get_arg(arg, sizeof(arg), &p);
1311 if (av_strcasecmp(arg, "allow") == 0)
1312 acl.action = IP_ALLOW;
1313 else if (av_strcasecmp(arg, "deny") == 0)
1314 acl.action = IP_DENY;
1316 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1317 filename, line_num, arg);
1321 get_arg(arg, sizeof(arg), &p);
1323 if (resolve_host(&acl.first, arg) != 0) {
1324 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1325 filename, line_num, arg);
1328 acl.last = acl.first;
1330 get_arg(arg, sizeof(arg), &p);
1333 if (resolve_host(&acl.last, arg) != 0) {
1334 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1335 filename, line_num, arg);
1341 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1342 IPAddressACL **naclp = 0;
1348 naclp = &stream->acl;
1354 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1355 filename, line_num);
1361 naclp = &(*naclp)->next;
1369 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1374 IPAddressACL *acl = NULL;
1378 f = fopen(stream->dynamic_acl, "r");
1380 perror(stream->dynamic_acl);
1384 acl = av_mallocz(sizeof(IPAddressACL));
1388 if (fgets(line, sizeof(line), f) == NULL)
1394 if (*p == '\0' || *p == '#')
1396 get_arg(cmd, sizeof(cmd), &p);
1398 if (!av_strcasecmp(cmd, "ACL"))
1399 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1406 static void free_acl_list(IPAddressACL *in_acl)
1408 IPAddressACL *pacl,*pacl2;
1418 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1420 enum IPAddressAction last_action = IP_DENY;
1422 struct in_addr *src = &c->from_addr.sin_addr;
1423 unsigned long src_addr = src->s_addr;
1425 for (acl = in_acl; acl; acl = acl->next) {
1426 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1427 return (acl->action == IP_ALLOW) ? 1 : 0;
1428 last_action = acl->action;
1431 /* Nothing matched, so return not the last action */
1432 return (last_action == IP_DENY) ? 1 : 0;
1435 static int validate_acl(FFStream *stream, HTTPContext *c)
1441 /* if stream->acl is null validate_acl_list will return 1 */
1442 ret = validate_acl_list(stream->acl, c);
1444 if (stream->dynamic_acl[0]) {
1445 acl = parse_dynamic_acl(stream, c);
1447 ret = validate_acl_list(acl, c);
1455 /* compute the real filename of a file by matching it without its
1456 extensions to all the stream filenames */
1457 static void compute_real_filename(char *filename, int max_size)
1464 /* compute filename by matching without the file extensions */
1465 av_strlcpy(file1, filename, sizeof(file1));
1466 p = strrchr(file1, '.');
1469 for(stream = first_stream; stream != NULL; stream = stream->next) {
1470 av_strlcpy(file2, stream->filename, sizeof(file2));
1471 p = strrchr(file2, '.');
1474 if (!strcmp(file1, file2)) {
1475 av_strlcpy(filename, stream->filename, max_size);
1490 /* parse http request and prepare header */
1491 static int http_parse_request(HTTPContext *c)
1495 enum RedirType redir_type;
1497 char info[1024], filename[1024];
1501 const char *mime_type;
1505 const char *useragent = 0;
1508 get_word(cmd, sizeof(cmd), &p);
1509 av_strlcpy(c->method, cmd, sizeof(c->method));
1511 if (!strcmp(cmd, "GET"))
1513 else if (!strcmp(cmd, "POST"))
1518 get_word(url, sizeof(url), &p);
1519 av_strlcpy(c->url, url, sizeof(c->url));
1521 get_word(protocol, sizeof(protocol), (const char **)&p);
1522 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1525 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1528 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1530 /* find the filename and the optional info string in the request */
1531 p1 = strchr(url, '?');
1533 av_strlcpy(info, p1, sizeof(info));
1538 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1540 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1541 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1543 if (*useragent && *useragent != '\n' && isspace(*useragent))
1547 p = strchr(p, '\n');
1554 redir_type = REDIR_NONE;
1555 if (av_match_ext(filename, "asx")) {
1556 redir_type = REDIR_ASX;
1557 filename[strlen(filename)-1] = 'f';
1558 } else if (av_match_ext(filename, "asf") &&
1559 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1560 /* if this isn't WMP or lookalike, return the redirector file */
1561 redir_type = REDIR_ASF;
1562 } else if (av_match_ext(filename, "rpm,ram")) {
1563 redir_type = REDIR_RAM;
1564 strcpy(filename + strlen(filename)-2, "m");
1565 } else if (av_match_ext(filename, "rtsp")) {
1566 redir_type = REDIR_RTSP;
1567 compute_real_filename(filename, sizeof(filename) - 1);
1568 } else if (av_match_ext(filename, "sdp")) {
1569 redir_type = REDIR_SDP;
1570 compute_real_filename(filename, sizeof(filename) - 1);
1573 // "redirect" / request to index.html
1574 if (!strlen(filename))
1575 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1577 stream = first_stream;
1578 while (stream != NULL) {
1579 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1581 stream = stream->next;
1583 if (stream == NULL) {
1584 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1585 http_log("File '%s' not found\n", url);
1590 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1591 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1593 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1594 c->http_error = 301;
1596 snprintf(q, c->buffer_size,
1597 "HTTP/1.0 301 Moved\r\n"
1599 "Content-type: text/html\r\n"
1601 "<html><head><title>Moved</title></head><body>\r\n"
1602 "You should be <a href=\"%s\">redirected</a>.\r\n"
1603 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1605 /* prepare output buffer */
1606 c->buffer_ptr = c->buffer;
1608 c->state = HTTPSTATE_SEND_HEADER;
1612 /* If this is WMP, get the rate information */
1613 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1614 if (modify_current_stream(c, ratebuf)) {
1615 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1616 if (c->switch_feed_streams[i] >= 0)
1617 c->switch_feed_streams[i] = -1;
1622 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1623 current_bandwidth += stream->bandwidth;
1625 /* If already streaming this feed, do not let start another feeder. */
1626 if (stream->feed_opened) {
1627 snprintf(msg, sizeof(msg), "This feed is already being received.");
1628 http_log("Feed '%s' already being received\n", stream->feed_filename);
1632 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1633 c->http_error = 503;
1635 snprintf(q, c->buffer_size,
1636 "HTTP/1.0 503 Server too busy\r\n"
1637 "Content-type: text/html\r\n"
1639 "<html><head><title>Too busy</title></head><body>\r\n"
1640 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1641 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1642 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1643 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1645 /* prepare output buffer */
1646 c->buffer_ptr = c->buffer;
1648 c->state = HTTPSTATE_SEND_HEADER;
1652 if (redir_type != REDIR_NONE) {
1653 const char *hostinfo = 0;
1655 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1656 if (av_strncasecmp(p, "Host:", 5) == 0) {
1660 p = strchr(p, '\n');
1671 while (isspace(*hostinfo))
1674 eoh = strchr(hostinfo, '\n');
1676 if (eoh[-1] == '\r')
1679 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1680 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1681 hostbuf[eoh - hostinfo] = 0;
1683 c->http_error = 200;
1685 switch(redir_type) {
1687 snprintf(q, c->buffer_size,
1688 "HTTP/1.0 200 ASX Follows\r\n"
1689 "Content-type: video/x-ms-asf\r\n"
1691 "<ASX Version=\"3\">\r\n"
1692 //"<!-- Autogenerated by ffserver -->\r\n"
1693 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1694 "</ASX>\r\n", hostbuf, filename, info);
1698 snprintf(q, c->buffer_size,
1699 "HTTP/1.0 200 RAM Follows\r\n"
1700 "Content-type: audio/x-pn-realaudio\r\n"
1702 "# Autogenerated by ffserver\r\n"
1703 "http://%s/%s%s\r\n", hostbuf, filename, info);
1707 snprintf(q, c->buffer_size,
1708 "HTTP/1.0 200 ASF Redirect follows\r\n"
1709 "Content-type: video/x-ms-asf\r\n"
1712 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1717 char hostname[256], *p;
1718 /* extract only hostname */
1719 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1720 p = strrchr(hostname, ':');
1723 snprintf(q, c->buffer_size,
1724 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1725 /* XXX: incorrect mime type ? */
1726 "Content-type: application/x-rtsp\r\n"
1728 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1737 struct sockaddr_in my_addr;
1739 snprintf(q, c->buffer_size,
1740 "HTTP/1.0 200 OK\r\n"
1741 "Content-type: application/sdp\r\n"
1745 len = sizeof(my_addr);
1746 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1748 /* XXX: should use a dynamic buffer */
1749 sdp_data_size = prepare_sdp_description(stream,
1752 if (sdp_data_size > 0) {
1753 memcpy(q, sdp_data, sdp_data_size);
1765 /* prepare output buffer */
1766 c->buffer_ptr = c->buffer;
1768 c->state = HTTPSTATE_SEND_HEADER;
1774 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1778 stream->conns_served++;
1780 /* XXX: add there authenticate and IP match */
1783 /* if post, it means a feed is being sent */
1784 if (!stream->is_feed) {
1785 /* However it might be a status report from WMP! Let us log the
1786 * data as it might come in handy one day. */
1787 const char *logline = 0;
1790 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1791 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1795 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1796 client_id = strtol(p + 18, 0, 10);
1797 p = strchr(p, '\n');
1805 char *eol = strchr(logline, '\n');
1810 if (eol[-1] == '\r')
1812 http_log("%.*s\n", (int) (eol - logline), logline);
1813 c->suppress_log = 1;
1818 http_log("\nGot request:\n%s\n", c->buffer);
1821 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1824 /* Now we have to find the client_id */
1825 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1826 if (wmpc->wmp_client_id == client_id)
1830 if (wmpc && modify_current_stream(wmpc, ratebuf))
1831 wmpc->switch_pending = 1;
1834 snprintf(msg, sizeof(msg), "POST command not handled");
1838 if (http_start_receive_data(c) < 0) {
1839 snprintf(msg, sizeof(msg), "could not open feed");
1843 c->state = HTTPSTATE_RECEIVE_DATA;
1848 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1849 http_log("\nGot request:\n%s\n", c->buffer);
1852 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1855 /* open input stream */
1856 if (open_input_stream(c, info) < 0) {
1857 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1861 /* prepare http header */
1863 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1864 mime_type = c->stream->fmt->mime_type;
1866 mime_type = "application/x-octet-stream";
1867 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1869 /* for asf, we need extra headers */
1870 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1871 /* Need to allocate a client id */
1873 c->wmp_client_id = av_lfg_get(&random_state);
1875 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);
1877 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1878 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1879 q = c->buffer + strlen(c->buffer);
1881 /* prepare output buffer */
1883 c->buffer_ptr = c->buffer;
1885 c->state = HTTPSTATE_SEND_HEADER;
1888 c->http_error = 404;
1890 snprintf(q, c->buffer_size,
1891 "HTTP/1.0 404 Not Found\r\n"
1892 "Content-type: text/html\r\n"
1895 "<head><title>404 Not Found</title></head>\n"
1899 /* prepare output buffer */
1900 c->buffer_ptr = c->buffer;
1902 c->state = HTTPSTATE_SEND_HEADER;
1906 c->http_error = 200; /* horrible : we use this value to avoid
1907 going to the send data state */
1908 c->state = HTTPSTATE_SEND_HEADER;
1912 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1914 static const char suffix[] = " kMGTP";
1917 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1919 avio_printf(pb, "%"PRId64"%c", count, *s);
1922 static void compute_status(HTTPContext *c)
1931 if (avio_open_dyn_buf(&pb) < 0) {
1932 /* XXX: return an error ? */
1933 c->buffer_ptr = c->buffer;
1934 c->buffer_end = c->buffer;
1938 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1939 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1940 avio_printf(pb, "Pragma: no-cache\r\n");
1941 avio_printf(pb, "\r\n");
1943 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1944 if (c->stream->feed_filename[0])
1945 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1946 avio_printf(pb, "</head>\n<body>");
1947 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1949 avio_printf(pb, "<h2>Available Streams</h2>\n");
1950 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1951 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");
1952 stream = first_stream;
1953 while (stream != NULL) {
1954 char sfilename[1024];
1957 if (stream->feed != stream) {
1958 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1959 eosf = sfilename + strlen(sfilename);
1960 if (eosf - sfilename >= 4) {
1961 if (strcmp(eosf - 4, ".asf") == 0)
1962 strcpy(eosf - 4, ".asx");
1963 else if (strcmp(eosf - 3, ".rm") == 0)
1964 strcpy(eosf - 3, ".ram");
1965 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1966 /* generate a sample RTSP director if
1967 unicast. Generate an SDP redirector if
1969 eosf = strrchr(sfilename, '.');
1971 eosf = sfilename + strlen(sfilename);
1972 if (stream->is_multicast)
1973 strcpy(eosf, ".sdp");
1975 strcpy(eosf, ".rtsp");
1979 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1980 sfilename, stream->filename);
1981 avio_printf(pb, "<td align=right> %d <td align=right> ",
1982 stream->conns_served);
1983 fmt_bytecount(pb, stream->bytes_served);
1984 switch(stream->stream_type) {
1985 case STREAM_TYPE_LIVE: {
1986 int audio_bit_rate = 0;
1987 int video_bit_rate = 0;
1988 const char *audio_codec_name = "";
1989 const char *video_codec_name = "";
1990 const char *audio_codec_name_extra = "";
1991 const char *video_codec_name_extra = "";
1993 for(i=0;i<stream->nb_streams;i++) {
1994 AVStream *st = stream->streams[i];
1995 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1996 switch(st->codec->codec_type) {
1997 case AVMEDIA_TYPE_AUDIO:
1998 audio_bit_rate += st->codec->bit_rate;
2000 if (*audio_codec_name)
2001 audio_codec_name_extra = "...";
2002 audio_codec_name = codec->name;
2005 case AVMEDIA_TYPE_VIDEO:
2006 video_bit_rate += st->codec->bit_rate;
2008 if (*video_codec_name)
2009 video_codec_name_extra = "...";
2010 video_codec_name = codec->name;
2013 case AVMEDIA_TYPE_DATA:
2014 video_bit_rate += st->codec->bit_rate;
2020 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",
2023 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2024 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2026 avio_printf(pb, "<td>%s", stream->feed->filename);
2028 avio_printf(pb, "<td>%s", stream->feed_filename);
2029 avio_printf(pb, "\n");
2033 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2037 stream = stream->next;
2039 avio_printf(pb, "</table>\n");
2041 stream = first_stream;
2042 while (stream != NULL) {
2043 if (stream->feed == stream) {
2044 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2046 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2053 /* This is somewhat linux specific I guess */
2054 snprintf(ps_cmd, sizeof(ps_cmd),
2055 "ps -o \"%%cpu,cputime\" --no-headers %d",
2058 pid_stat = popen(ps_cmd, "r");
2063 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2065 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2073 avio_printf(pb, "<p>");
2075 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");
2077 for (i = 0; i < stream->nb_streams; i++) {
2078 AVStream *st = stream->streams[i];
2079 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2080 const char *type = "unknown";
2081 char parameters[64];
2085 switch(st->codec->codec_type) {
2086 case AVMEDIA_TYPE_AUDIO:
2088 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2090 case AVMEDIA_TYPE_VIDEO:
2092 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2093 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2098 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2099 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2101 avio_printf(pb, "</table>\n");
2104 stream = stream->next;
2107 /* connection status */
2108 avio_printf(pb, "<h2>Connection Status</h2>\n");
2110 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2111 nb_connections, nb_max_connections);
2113 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2114 current_bandwidth, max_bandwidth);
2116 avio_printf(pb, "<table>\n");
2117 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");
2118 c1 = first_http_ctx;
2120 while (c1 != NULL) {
2126 for (j = 0; j < c1->stream->nb_streams; j++) {
2127 if (!c1->stream->feed)
2128 bitrate += c1->stream->streams[j]->codec->bit_rate;
2129 else if (c1->feed_streams[j] >= 0)
2130 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2135 p = inet_ntoa(c1->from_addr.sin_addr);
2136 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2138 c1->stream ? c1->stream->filename : "",
2139 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2142 http_state[c1->state]);
2143 fmt_bytecount(pb, bitrate);
2144 avio_printf(pb, "<td align=right>");
2145 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2146 avio_printf(pb, "<td align=right>");
2147 fmt_bytecount(pb, c1->data_count);
2148 avio_printf(pb, "\n");
2151 avio_printf(pb, "</table>\n");
2156 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2157 avio_printf(pb, "</body>\n</html>\n");
2159 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2160 c->buffer_ptr = c->pb_buffer;
2161 c->buffer_end = c->pb_buffer + len;
2164 static int open_input_stream(HTTPContext *c, const char *info)
2167 char input_filename[1024];
2168 AVFormatContext *s = NULL;
2169 int buf_size, i, ret;
2172 /* find file name */
2173 if (c->stream->feed) {
2174 strcpy(input_filename, c->stream->feed->feed_filename);
2175 buf_size = FFM_PACKET_SIZE;
2176 /* compute position (absolute time) */
2177 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2178 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2180 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2181 int prebuffer = strtol(buf, 0, 10);
2182 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2184 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2186 strcpy(input_filename, c->stream->feed_filename);
2188 /* compute position (relative time) */
2189 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2190 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2195 if (input_filename[0] == '\0')
2199 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2200 http_log("could not open %s: %d\n", input_filename, ret);
2204 /* set buffer size */
2205 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2207 s->flags |= AVFMT_FLAG_GENPTS;
2209 if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
2210 http_log("Could not find stream info '%s'\n", input_filename);
2211 avformat_close_input(&s);
2215 /* choose stream as clock source (we favorize video stream if
2216 present) for packet sending */
2217 c->pts_stream_index = 0;
2218 for(i=0;i<c->stream->nb_streams;i++) {
2219 if (c->pts_stream_index == 0 &&
2220 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2221 c->pts_stream_index = i;
2225 if (c->fmt_in->iformat->read_seek)
2226 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2227 /* set the start time (needed for maxtime and RTP packet timing) */
2228 c->start_time = cur_time;
2229 c->first_pts = AV_NOPTS_VALUE;
2233 /* return the server clock (in us) */
2234 static int64_t get_server_clock(HTTPContext *c)
2236 /* compute current pts value from system time */
2237 return (cur_time - c->start_time) * 1000;
2240 /* return the estimated time at which the current packet must be sent
2242 static int64_t get_packet_send_clock(HTTPContext *c)
2244 int bytes_left, bytes_sent, frame_bytes;
2246 frame_bytes = c->cur_frame_bytes;
2247 if (frame_bytes <= 0)
2250 bytes_left = c->buffer_end - c->buffer_ptr;
2251 bytes_sent = frame_bytes - bytes_left;
2252 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2257 static int http_prepare_data(HTTPContext *c)
2260 AVFormatContext *ctx;
2262 av_freep(&c->pb_buffer);
2264 case HTTPSTATE_SEND_DATA_HEADER:
2265 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2266 av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2267 av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2268 av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2269 av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2271 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2273 for(i=0;i<c->stream->nb_streams;i++) {
2275 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2276 /* if file or feed, then just take streams from FFStream struct */
2277 if (!c->stream->feed ||
2278 c->stream->feed == c->stream)
2279 src = c->stream->streams[i];
2281 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2283 *(c->fmt_ctx.streams[i]) = *src;
2284 c->fmt_ctx.streams[i]->priv_data = 0;
2285 c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2286 AVStream, not in codec */
2288 /* set output format parameters */
2289 c->fmt_ctx.oformat = c->stream->fmt;
2290 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2292 c->got_key_frame = 0;
2294 /* prepare header and save header data in a stream */
2295 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2296 /* XXX: potential leak */
2299 c->fmt_ctx.pb->seekable = 0;
2302 * HACK to avoid mpeg ps muxer to spit many underflow errors
2303 * Default value from FFmpeg
2304 * Try to set it use configuration option
2306 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2308 if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2309 http_log("Error writing output header\n");
2312 av_dict_free(&c->fmt_ctx.metadata);
2314 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2315 c->buffer_ptr = c->pb_buffer;
2316 c->buffer_end = c->pb_buffer + len;
2318 c->state = HTTPSTATE_SEND_DATA;
2319 c->last_packet_sent = 0;
2321 case HTTPSTATE_SEND_DATA:
2322 /* find a new packet */
2323 /* read a packet from the input stream */
2324 if (c->stream->feed)
2325 ffm_set_write_index(c->fmt_in,
2326 c->stream->feed->feed_write_index,
2327 c->stream->feed->feed_size);
2329 if (c->stream->max_time &&
2330 c->stream->max_time + c->start_time - cur_time < 0)
2331 /* We have timed out */
2332 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2336 ret = av_read_frame(c->fmt_in, &pkt);
2338 if (c->stream->feed) {
2339 /* if coming from feed, it means we reached the end of the
2340 ffm file, so must wait for more data */
2341 c->state = HTTPSTATE_WAIT_FEED;
2342 return 1; /* state changed */
2343 } else if (ret == AVERROR(EAGAIN)) {
2344 /* input not ready, come back later */
2347 if (c->stream->loop) {
2348 avformat_close_input(&c->fmt_in);
2349 if (open_input_stream(c, "") < 0)
2354 /* must send trailer now because eof or error */
2355 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2359 int source_index = pkt.stream_index;
2360 /* update first pts if needed */
2361 if (c->first_pts == AV_NOPTS_VALUE) {
2362 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2363 c->start_time = cur_time;
2365 /* send it to the appropriate stream */
2366 if (c->stream->feed) {
2367 /* if coming from a feed, select the right stream */
2368 if (c->switch_pending) {
2369 c->switch_pending = 0;
2370 for(i=0;i<c->stream->nb_streams;i++) {
2371 if (c->switch_feed_streams[i] == pkt.stream_index)
2372 if (pkt.flags & AV_PKT_FLAG_KEY)
2373 c->switch_feed_streams[i] = -1;
2374 if (c->switch_feed_streams[i] >= 0)
2375 c->switch_pending = 1;
2378 for(i=0;i<c->stream->nb_streams;i++) {
2379 if (c->stream->feed_streams[i] == pkt.stream_index) {
2380 AVStream *st = c->fmt_in->streams[source_index];
2381 pkt.stream_index = i;
2382 if (pkt.flags & AV_PKT_FLAG_KEY &&
2383 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2384 c->stream->nb_streams == 1))
2385 c->got_key_frame = 1;
2386 if (!c->stream->send_on_key || c->got_key_frame)
2391 AVCodecContext *codec;
2392 AVStream *ist, *ost;
2394 ist = c->fmt_in->streams[source_index];
2395 /* specific handling for RTP: we use several
2396 output stream (one for each RTP
2397 connection). XXX: need more abstract handling */
2398 if (c->is_packetized) {
2399 /* compute send time and duration */
2400 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2401 c->cur_pts -= c->first_pts;
2402 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2403 /* find RTP context */
2404 c->packet_stream_index = pkt.stream_index;
2405 ctx = c->rtp_ctx[c->packet_stream_index];
2407 av_free_packet(&pkt);
2410 codec = ctx->streams[0]->codec;
2411 /* only one stream per RTP connection */
2412 pkt.stream_index = 0;
2416 codec = ctx->streams[pkt.stream_index]->codec;
2419 if (c->is_packetized) {
2420 int max_packet_size;
2421 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2422 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2424 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2425 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2427 ret = avio_open_dyn_buf(&ctx->pb);
2430 /* XXX: potential leak */
2433 ost = ctx->streams[pkt.stream_index];
2435 ctx->pb->seekable = 0;
2436 if (pkt.dts != AV_NOPTS_VALUE)
2437 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2438 if (pkt.pts != AV_NOPTS_VALUE)
2439 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2440 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2441 if (av_write_frame(ctx, &pkt) < 0) {
2442 http_log("Error writing frame to output\n");
2443 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2446 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2447 c->cur_frame_bytes = len;
2448 c->buffer_ptr = c->pb_buffer;
2449 c->buffer_end = c->pb_buffer + len;
2451 codec->frame_number++;
2453 av_free_packet(&pkt);
2457 av_free_packet(&pkt);
2462 case HTTPSTATE_SEND_DATA_TRAILER:
2463 /* last packet test ? */
2464 if (c->last_packet_sent || c->is_packetized)
2467 /* prepare header */
2468 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2469 /* XXX: potential leak */
2472 c->fmt_ctx.pb->seekable = 0;
2473 av_write_trailer(ctx);
2474 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2475 c->buffer_ptr = c->pb_buffer;
2476 c->buffer_end = c->pb_buffer + len;
2478 c->last_packet_sent = 1;
2484 /* should convert the format at the same time */
2485 /* send data starting at c->buffer_ptr to the output connection
2486 (either UDP or TCP connection) */
2487 static int http_send_data(HTTPContext *c)
2492 if (c->buffer_ptr >= c->buffer_end) {
2493 ret = http_prepare_data(c);
2497 /* state change requested */
2500 if (c->is_packetized) {
2501 /* RTP data output */
2502 len = c->buffer_end - c->buffer_ptr;
2504 /* fail safe - should never happen */
2506 c->buffer_ptr = c->buffer_end;
2509 len = (c->buffer_ptr[0] << 24) |
2510 (c->buffer_ptr[1] << 16) |
2511 (c->buffer_ptr[2] << 8) |
2513 if (len > (c->buffer_end - c->buffer_ptr))
2515 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2516 /* nothing to send yet: we can wait */
2520 c->data_count += len;
2521 update_datarate(&c->datarate, c->data_count);
2523 c->stream->bytes_served += len;
2525 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2526 /* RTP packets are sent inside the RTSP TCP connection */
2528 int interleaved_index, size;
2530 HTTPContext *rtsp_c;
2533 /* if no RTSP connection left, error */
2536 /* if already sending something, then wait. */
2537 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2539 if (avio_open_dyn_buf(&pb) < 0)
2541 interleaved_index = c->packet_stream_index * 2;
2542 /* RTCP packets are sent at odd indexes */
2543 if (c->buffer_ptr[1] == 200)
2544 interleaved_index++;
2545 /* write RTSP TCP header */
2547 header[1] = interleaved_index;
2548 header[2] = len >> 8;
2550 avio_write(pb, header, 4);
2551 /* write RTP packet data */
2553 avio_write(pb, c->buffer_ptr, len);
2554 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2555 /* prepare asynchronous TCP sending */
2556 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2557 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2558 c->buffer_ptr += len;
2560 /* send everything we can NOW */
2561 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2562 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2564 rtsp_c->packet_buffer_ptr += len;
2565 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2566 /* if we could not send all the data, we will
2567 send it later, so a new state is needed to
2568 "lock" the RTSP TCP connection */
2569 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2572 /* all data has been sent */
2573 av_freep(&c->packet_buffer);
2575 /* send RTP packet directly in UDP */
2577 ffurl_write(c->rtp_handles[c->packet_stream_index],
2578 c->buffer_ptr, len);
2579 c->buffer_ptr += len;
2580 /* here we continue as we can send several packets per 10 ms slot */
2583 /* TCP data output */
2584 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2586 if (ff_neterrno() != AVERROR(EAGAIN) &&
2587 ff_neterrno() != AVERROR(EINTR))
2588 /* error : close connection */
2593 c->buffer_ptr += len;
2595 c->data_count += len;
2596 update_datarate(&c->datarate, c->data_count);
2598 c->stream->bytes_served += len;
2606 static int http_start_receive_data(HTTPContext *c)
2610 if (c->stream->feed_opened)
2613 /* Don't permit writing to this one */
2614 if (c->stream->readonly)
2618 fd = open(c->stream->feed_filename, O_RDWR);
2620 http_log("Error opening feeder file: %s\n", strerror(errno));
2625 if (c->stream->truncate) {
2626 /* truncate feed file */
2627 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2628 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2629 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2630 http_log("Error truncating feed file: %s\n", strerror(errno));
2634 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2635 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2640 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2641 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2642 lseek(fd, 0, SEEK_SET);
2644 /* init buffer input */
2645 c->buffer_ptr = c->buffer;
2646 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2647 c->stream->feed_opened = 1;
2648 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2652 static int http_receive_data(HTTPContext *c)
2655 int len, loop_run = 0;
2657 while (c->chunked_encoding && !c->chunk_size &&
2658 c->buffer_end > c->buffer_ptr) {
2659 /* read chunk header, if present */
2660 len = recv(c->fd, c->buffer_ptr, 1, 0);
2663 if (ff_neterrno() != AVERROR(EAGAIN) &&
2664 ff_neterrno() != AVERROR(EINTR))
2665 /* error : close connection */
2668 } else if (len == 0) {
2669 /* end of connection : close it */
2671 } else if (c->buffer_ptr - c->buffer >= 2 &&
2672 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2673 c->chunk_size = strtol(c->buffer, 0, 16);
2674 if (c->chunk_size == 0) // end of stream
2676 c->buffer_ptr = c->buffer;
2678 } else if (++loop_run > 10) {
2679 /* no chunk header, abort */
2686 if (c->buffer_end > c->buffer_ptr) {
2687 len = recv(c->fd, c->buffer_ptr,
2688 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2690 if (ff_neterrno() != AVERROR(EAGAIN) &&
2691 ff_neterrno() != AVERROR(EINTR))
2692 /* error : close connection */
2694 } else if (len == 0)
2695 /* end of connection : close it */
2698 c->chunk_size -= len;
2699 c->buffer_ptr += len;
2700 c->data_count += len;
2701 update_datarate(&c->datarate, c->data_count);
2705 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2706 if (c->buffer[0] != 'f' ||
2707 c->buffer[1] != 'm') {
2708 http_log("Feed stream has become desynchronized -- disconnecting\n");
2713 if (c->buffer_ptr >= c->buffer_end) {
2714 FFStream *feed = c->stream;
2715 /* a packet has been received : write it in the store, except
2717 if (c->data_count > FFM_PACKET_SIZE) {
2718 /* XXX: use llseek or url_seek */
2719 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2720 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2721 http_log("Error writing to feed file: %s\n", strerror(errno));
2725 feed->feed_write_index += FFM_PACKET_SIZE;
2726 /* update file size */
2727 if (feed->feed_write_index > c->stream->feed_size)
2728 feed->feed_size = feed->feed_write_index;
2730 /* handle wrap around if max file size reached */
2731 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2732 feed->feed_write_index = FFM_PACKET_SIZE;
2735 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2736 http_log("Error writing index to feed file: %s\n", strerror(errno));
2740 /* wake up any waiting connections */
2741 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2742 if (c1->state == HTTPSTATE_WAIT_FEED &&
2743 c1->stream->feed == c->stream->feed)
2744 c1->state = HTTPSTATE_SEND_DATA;
2747 /* We have a header in our hands that contains useful data */
2748 AVFormatContext *s = avformat_alloc_context();
2750 AVInputFormat *fmt_in;
2756 /* use feed output format name to find corresponding input format */
2757 fmt_in = av_find_input_format(feed->fmt->name);
2761 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2762 0, NULL, NULL, NULL, NULL);
2766 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2771 /* Now we have the actual streams */
2772 if (s->nb_streams != feed->nb_streams) {
2773 avformat_close_input(&s);
2775 http_log("Feed '%s' stream number does not match registered feed\n",
2776 c->stream->feed_filename);
2780 for (i = 0; i < s->nb_streams; i++) {
2781 AVStream *fst = feed->streams[i];
2782 AVStream *st = s->streams[i];
2783 avcodec_copy_context(fst->codec, st->codec);
2786 avformat_close_input(&s);
2789 c->buffer_ptr = c->buffer;
2794 c->stream->feed_opened = 0;
2796 /* wake up any waiting connections to stop waiting for feed */
2797 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2798 if (c1->state == HTTPSTATE_WAIT_FEED &&
2799 c1->stream->feed == c->stream->feed)
2800 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2805 /********************************************************************/
2808 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2815 switch(error_number) {
2816 case RTSP_STATUS_OK:
2819 case RTSP_STATUS_METHOD:
2820 str = "Method Not Allowed";
2822 case RTSP_STATUS_BANDWIDTH:
2823 str = "Not Enough Bandwidth";
2825 case RTSP_STATUS_SESSION:
2826 str = "Session Not Found";
2828 case RTSP_STATUS_STATE:
2829 str = "Method Not Valid in This State";
2831 case RTSP_STATUS_AGGREGATE:
2832 str = "Aggregate operation not allowed";
2834 case RTSP_STATUS_ONLY_AGGREGATE:
2835 str = "Only aggregate operation allowed";
2837 case RTSP_STATUS_TRANSPORT:
2838 str = "Unsupported transport";
2840 case RTSP_STATUS_INTERNAL:
2841 str = "Internal Server Error";
2843 case RTSP_STATUS_SERVICE:
2844 str = "Service Unavailable";
2846 case RTSP_STATUS_VERSION:
2847 str = "RTSP Version not supported";
2850 str = "Unknown Error";
2854 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2855 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2857 /* output GMT time */
2860 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2861 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2864 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2866 rtsp_reply_header(c, error_number);
2867 avio_printf(c->pb, "\r\n");
2870 static int rtsp_parse_request(HTTPContext *c)
2872 const char *p, *p1, *p2;
2878 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2880 c->buffer_ptr[0] = '\0';
2883 get_word(cmd, sizeof(cmd), &p);
2884 get_word(url, sizeof(url), &p);
2885 get_word(protocol, sizeof(protocol), &p);
2887 av_strlcpy(c->method, cmd, sizeof(c->method));
2888 av_strlcpy(c->url, url, sizeof(c->url));
2889 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2891 if (avio_open_dyn_buf(&c->pb) < 0) {
2892 /* XXX: cannot do more */
2893 c->pb = NULL; /* safety */
2897 /* check version name */
2898 if (strcmp(protocol, "RTSP/1.0") != 0) {
2899 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2903 /* parse each header line */
2904 /* skip to next line */
2905 while (*p != '\n' && *p != '\0')
2909 while (*p != '\0') {
2910 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2914 if (p2 > p && p2[-1] == '\r')
2916 /* skip empty line */
2920 if (len > sizeof(line) - 1)
2921 len = sizeof(line) - 1;
2922 memcpy(line, p, len);
2924 ff_rtsp_parse_line(header, line, NULL, NULL);
2928 /* handle sequence number */
2929 c->seq = header->seq;
2931 if (!strcmp(cmd, "DESCRIBE"))
2932 rtsp_cmd_describe(c, url);
2933 else if (!strcmp(cmd, "OPTIONS"))
2934 rtsp_cmd_options(c, url);
2935 else if (!strcmp(cmd, "SETUP"))
2936 rtsp_cmd_setup(c, url, header);
2937 else if (!strcmp(cmd, "PLAY"))
2938 rtsp_cmd_play(c, url, header);
2939 else if (!strcmp(cmd, "PAUSE"))
2940 rtsp_cmd_pause(c, url, header);
2941 else if (!strcmp(cmd, "TEARDOWN"))
2942 rtsp_cmd_teardown(c, url, header);
2944 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2947 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2948 c->pb = NULL; /* safety */
2950 /* XXX: cannot do more */
2953 c->buffer_ptr = c->pb_buffer;
2954 c->buffer_end = c->pb_buffer + len;
2955 c->state = RTSPSTATE_SEND_REPLY;
2959 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2960 struct in_addr my_ip)
2962 AVFormatContext *avc;
2963 AVStream *avs = NULL;
2966 avc = avformat_alloc_context();
2970 av_dict_set(&avc->metadata, "title",
2971 stream->title[0] ? stream->title : "No Title", 0);
2972 avc->nb_streams = stream->nb_streams;
2973 if (stream->is_multicast) {
2974 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2975 inet_ntoa(stream->multicast_ip),
2976 stream->multicast_port, stream->multicast_ttl);
2978 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2981 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2982 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2984 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2985 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2988 for(i = 0; i < stream->nb_streams; i++) {
2989 avc->streams[i] = &avs[i];
2990 avc->streams[i]->codec = stream->streams[i]->codec;
2992 *pbuffer = av_mallocz(2048);
2993 av_sdp_create(&avc, 1, *pbuffer, 2048);
2996 av_free(avc->streams);
2997 av_dict_free(&avc->metadata);
3001 return strlen(*pbuffer);
3004 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3006 // rtsp_reply_header(c, RTSP_STATUS_OK);
3007 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3008 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3009 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3010 avio_printf(c->pb, "\r\n");
3013 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3021 struct sockaddr_in my_addr;
3023 /* find which url is asked */
3024 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3029 for(stream = first_stream; stream != NULL; stream = stream->next) {
3030 if (!stream->is_feed &&
3031 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3032 !strcmp(path, stream->filename)) {
3036 /* no stream found */
3037 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3041 /* prepare the media description in sdp format */
3043 /* get the host IP */
3044 len = sizeof(my_addr);
3045 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3046 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3047 if (content_length < 0) {
3048 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3051 rtsp_reply_header(c, RTSP_STATUS_OK);
3052 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3053 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3054 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3055 avio_printf(c->pb, "\r\n");
3056 avio_write(c->pb, content, content_length);
3060 static HTTPContext *find_rtp_session(const char *session_id)
3064 if (session_id[0] == '\0')
3067 for(c = first_http_ctx; c != NULL; c = c->next) {
3068 if (!strcmp(c->session_id, session_id))
3074 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3076 RTSPTransportField *th;
3079 for(i=0;i<h->nb_transports;i++) {
3080 th = &h->transports[i];
3081 if (th->lower_transport == lower_transport)
3087 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3088 RTSPMessageHeader *h)
3091 int stream_index, rtp_port, rtcp_port;
3096 RTSPTransportField *th;
3097 struct sockaddr_in dest_addr;
3098 RTSPActionServerSetup setup;
3100 /* find which url is asked */
3101 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3106 /* now check each stream */
3107 for(stream = first_stream; stream != NULL; stream = stream->next) {
3108 if (!stream->is_feed &&
3109 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3110 /* accept aggregate filenames only if single stream */
3111 if (!strcmp(path, stream->filename)) {
3112 if (stream->nb_streams != 1) {
3113 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3120 for(stream_index = 0; stream_index < stream->nb_streams;
3122 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3123 stream->filename, stream_index);
3124 if (!strcmp(path, buf))
3129 /* no stream found */
3130 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3134 /* generate session id if needed */
3135 if (h->session_id[0] == '\0') {
3136 unsigned random0 = av_lfg_get(&random_state);
3137 unsigned random1 = av_lfg_get(&random_state);
3138 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3142 /* find rtp session, and create it if none found */
3143 rtp_c = find_rtp_session(h->session_id);
3145 /* always prefer UDP */
3146 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3148 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3150 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3155 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3156 th->lower_transport);
3158 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3162 /* open input stream */
3163 if (open_input_stream(rtp_c, "") < 0) {
3164 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3169 /* test if stream is OK (test needed because several SETUP needs
3170 to be done for a given file) */
3171 if (rtp_c->stream != stream) {
3172 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3176 /* test if stream is already set up */
3177 if (rtp_c->rtp_ctx[stream_index]) {
3178 rtsp_reply_error(c, RTSP_STATUS_STATE);
3182 /* check transport */
3183 th = find_transport(h, rtp_c->rtp_protocol);
3184 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3185 th->client_port_min <= 0)) {
3186 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3190 /* setup default options */
3191 setup.transport_option[0] = '\0';
3192 dest_addr = rtp_c->from_addr;
3193 dest_addr.sin_port = htons(th->client_port_min);
3196 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3197 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3201 /* now everything is OK, so we can send the connection parameters */
3202 rtsp_reply_header(c, RTSP_STATUS_OK);
3204 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3206 switch(rtp_c->rtp_protocol) {
3207 case RTSP_LOWER_TRANSPORT_UDP:
3208 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3209 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3210 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3211 "client_port=%d-%d;server_port=%d-%d",
3212 th->client_port_min, th->client_port_max,
3213 rtp_port, rtcp_port);
3215 case RTSP_LOWER_TRANSPORT_TCP:
3216 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3217 stream_index * 2, stream_index * 2 + 1);
3222 if (setup.transport_option[0] != '\0')
3223 avio_printf(c->pb, ";%s", setup.transport_option);
3224 avio_printf(c->pb, "\r\n");
3227 avio_printf(c->pb, "\r\n");
3231 /* find an rtp connection by using the session ID. Check consistency
3233 static HTTPContext *find_rtp_session_with_url(const char *url,
3234 const char *session_id)
3242 rtp_c = find_rtp_session(session_id);
3246 /* find which url is asked */
3247 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3251 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3252 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3253 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3254 rtp_c->stream->filename, s);
3255 if(!strncmp(path, buf, sizeof(buf))) {
3256 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3261 if (len > 0 && path[len - 1] == '/' &&
3262 !strncmp(path, rtp_c->stream->filename, len - 1))
3267 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3271 rtp_c = find_rtp_session_with_url(url, h->session_id);
3273 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3277 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3278 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3279 rtp_c->state != HTTPSTATE_READY) {
3280 rtsp_reply_error(c, RTSP_STATUS_STATE);
3284 rtp_c->state = HTTPSTATE_SEND_DATA;
3286 /* now everything is OK, so we can send the connection parameters */
3287 rtsp_reply_header(c, RTSP_STATUS_OK);
3289 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3290 avio_printf(c->pb, "\r\n");
3293 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3297 rtp_c = find_rtp_session_with_url(url, h->session_id);
3299 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3303 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3304 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3305 rtsp_reply_error(c, RTSP_STATUS_STATE);
3309 rtp_c->state = HTTPSTATE_READY;
3310 rtp_c->first_pts = AV_NOPTS_VALUE;
3311 /* now everything is OK, so we can send the connection parameters */
3312 rtsp_reply_header(c, RTSP_STATUS_OK);
3314 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3315 avio_printf(c->pb, "\r\n");
3318 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3322 rtp_c = find_rtp_session_with_url(url, h->session_id);
3324 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3328 /* now everything is OK, so we can send the connection parameters */
3329 rtsp_reply_header(c, RTSP_STATUS_OK);
3331 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3332 avio_printf(c->pb, "\r\n");
3334 /* abort the session */
3335 close_connection(rtp_c);
3339 /********************************************************************/
3342 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3343 FFStream *stream, const char *session_id,
3344 enum RTSPLowerTransport rtp_protocol)
3346 HTTPContext *c = NULL;
3347 const char *proto_str;
3349 /* XXX: should output a warning page when coming
3350 close to the connection limit */
3351 if (nb_connections >= nb_max_connections)
3354 /* add a new connection */
3355 c = av_mallocz(sizeof(HTTPContext));
3360 c->poll_entry = NULL;
3361 c->from_addr = *from_addr;
3362 c->buffer_size = IOBUFFER_INIT_SIZE;
3363 c->buffer = av_malloc(c->buffer_size);
3368 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3369 c->state = HTTPSTATE_READY;
3370 c->is_packetized = 1;
3371 c->rtp_protocol = rtp_protocol;
3373 /* protocol is shown in statistics */
3374 switch(c->rtp_protocol) {
3375 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3376 proto_str = "MCAST";
3378 case RTSP_LOWER_TRANSPORT_UDP:
3381 case RTSP_LOWER_TRANSPORT_TCP:
3388 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3389 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3391 current_bandwidth += stream->bandwidth;
3393 c->next = first_http_ctx;
3405 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3406 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3408 static int rtp_new_av_stream(HTTPContext *c,
3409 int stream_index, struct sockaddr_in *dest_addr,
3410 HTTPContext *rtsp_c)
3412 AVFormatContext *ctx;
3415 URLContext *h = NULL;
3417 int max_packet_size;
3419 /* now we can open the relevant output stream */
3420 ctx = avformat_alloc_context();
3423 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3425 st = av_mallocz(sizeof(AVStream));
3428 ctx->nb_streams = 1;
3429 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3432 ctx->streams[0] = st;
3434 if (!c->stream->feed ||
3435 c->stream->feed == c->stream)
3436 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3439 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3441 st->priv_data = NULL;
3443 /* build destination RTP address */
3444 ipaddr = inet_ntoa(dest_addr->sin_addr);
3446 switch(c->rtp_protocol) {
3447 case RTSP_LOWER_TRANSPORT_UDP:
3448 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3451 /* XXX: also pass as parameter to function ? */
3452 if (c->stream->is_multicast) {
3454 ttl = c->stream->multicast_ttl;
3457 snprintf(ctx->filename, sizeof(ctx->filename),
3458 "rtp://%s:%d?multicast=1&ttl=%d",
3459 ipaddr, ntohs(dest_addr->sin_port), ttl);
3461 snprintf(ctx->filename, sizeof(ctx->filename),
3462 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3465 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3467 c->rtp_handles[stream_index] = h;
3468 max_packet_size = h->max_packet_size;
3470 case RTSP_LOWER_TRANSPORT_TCP:
3473 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3479 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3480 ipaddr, ntohs(dest_addr->sin_port),
3481 c->stream->filename, stream_index, c->protocol);
3483 /* normally, no packets should be output here, but the packet size may be checked */
3484 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3485 /* XXX: close stream */
3488 if (avformat_write_header(ctx, NULL) < 0) {
3495 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3498 c->rtp_ctx[stream_index] = ctx;
3502 /********************************************************************/
3503 /* ffserver initialization */
3505 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3509 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3512 fst = av_mallocz(sizeof(AVStream));
3516 fst->codec = avcodec_alloc_context3(NULL);
3517 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3518 if (codec->extradata_size) {
3519 fst->codec->extradata = av_malloc(codec->extradata_size);
3520 memcpy(fst->codec->extradata, codec->extradata,
3521 codec->extradata_size);
3524 /* live streams must use the actual feed's codec since it may be
3525 * updated later to carry extradata needed by the streams.
3529 fst->priv_data = av_mallocz(sizeof(FeedData));
3530 fst->index = stream->nb_streams;
3531 avpriv_set_pts_info(fst, 33, 1, 90000);
3532 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3533 stream->streams[stream->nb_streams++] = fst;
3537 /* return the stream number in the feed */
3538 static int add_av_stream(FFStream *feed, AVStream *st)
3541 AVCodecContext *av, *av1;
3545 for(i=0;i<feed->nb_streams;i++) {
3546 st = feed->streams[i];
3548 if (av1->codec_id == av->codec_id &&
3549 av1->codec_type == av->codec_type &&
3550 av1->bit_rate == av->bit_rate) {
3552 switch(av->codec_type) {
3553 case AVMEDIA_TYPE_AUDIO:
3554 if (av1->channels == av->channels &&
3555 av1->sample_rate == av->sample_rate)
3558 case AVMEDIA_TYPE_VIDEO:
3559 if (av1->width == av->width &&
3560 av1->height == av->height &&
3561 av1->time_base.den == av->time_base.den &&
3562 av1->time_base.num == av->time_base.num &&
3563 av1->gop_size == av->gop_size)
3572 fst = add_av_stream1(feed, av, 0);
3575 return feed->nb_streams - 1;
3578 static void remove_stream(FFStream *stream)
3582 while (*ps != NULL) {
3590 /* specific mpeg4 handling : we extract the raw parameters */
3591 static void extract_mpeg4_header(AVFormatContext *infile)
3593 int mpeg4_count, i, size;
3598 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3601 for(i=0;i<infile->nb_streams;i++) {
3602 st = infile->streams[i];
3603 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3604 st->codec->extradata_size == 0) {
3611 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3612 while (mpeg4_count > 0) {
3613 if (av_read_frame(infile, &pkt) < 0)
3615 st = infile->streams[pkt.stream_index];
3616 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3617 st->codec->extradata_size == 0) {
3618 av_freep(&st->codec->extradata);
3619 /* fill extradata with the header */
3620 /* XXX: we make hard suppositions here ! */
3622 while (p < pkt.data + pkt.size - 4) {
3623 /* stop when vop header is found */
3624 if (p[0] == 0x00 && p[1] == 0x00 &&
3625 p[2] == 0x01 && p[3] == 0xb6) {
3626 size = p - pkt.data;
3627 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3628 st->codec->extradata = av_malloc(size);
3629 st->codec->extradata_size = size;
3630 memcpy(st->codec->extradata, pkt.data, size);
3637 av_free_packet(&pkt);
3641 /* compute the needed AVStream for each file */
3642 static void build_file_streams(void)
3644 FFStream *stream, *stream_next;
3647 /* gather all streams */
3648 for(stream = first_stream; stream != NULL; stream = stream_next) {
3649 AVFormatContext *infile = NULL;
3650 stream_next = stream->next;
3651 if (stream->stream_type == STREAM_TYPE_LIVE &&
3653 /* the stream comes from a file */
3654 /* try to open the file */
3656 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3657 /* specific case : if transport stream output to RTP,
3658 we use a raw transport stream reader */
3659 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3662 http_log("Opening file '%s'\n", stream->feed_filename);
3663 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3664 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3665 /* remove stream (no need to spend more time on it) */
3667 remove_stream(stream);
3669 /* find all the AVStreams inside and reference them in
3671 if (avformat_find_stream_info(infile, NULL) < 0) {
3672 http_log("Could not find codec parameters from '%s'\n",
3673 stream->feed_filename);
3674 avformat_close_input(&infile);
3677 extract_mpeg4_header(infile);
3679 for(i=0;i<infile->nb_streams;i++)
3680 add_av_stream1(stream, infile->streams[i]->codec, 1);
3682 avformat_close_input(&infile);
3688 /* compute the needed AVStream for each feed */
3689 static void build_feed_streams(void)
3691 FFStream *stream, *feed;
3694 /* gather all streams */
3695 for(stream = first_stream; stream != NULL; stream = stream->next) {
3696 feed = stream->feed;
3698 if (stream->is_feed) {
3699 for(i=0;i<stream->nb_streams;i++)
3700 stream->feed_streams[i] = i;
3702 /* we handle a stream coming from a feed */
3703 for(i=0;i<stream->nb_streams;i++)
3704 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3709 /* create feed files if needed */
3710 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3713 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3714 /* See if it matches */
3715 AVFormatContext *s = NULL;
3718 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3719 /* set buffer size */
3720 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3721 /* Now see if it matches */
3722 if (s->nb_streams == feed->nb_streams) {
3724 for(i=0;i<s->nb_streams;i++) {
3726 sf = feed->streams[i];
3729 if (sf->index != ss->index ||
3731 http_log("Index & Id do not match for stream %d (%s)\n",
3732 i, feed->feed_filename);
3735 AVCodecContext *ccf, *ccs;
3739 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3741 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3742 http_log("Codecs do not match for stream %d\n", i);
3744 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3745 http_log("Codec bitrates do not match for stream %d\n", i);
3747 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3748 if (CHECK_CODEC(time_base.den) ||
3749 CHECK_CODEC(time_base.num) ||
3750 CHECK_CODEC(width) ||
3751 CHECK_CODEC(height)) {
3752 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3755 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3756 if (CHECK_CODEC(sample_rate) ||
3757 CHECK_CODEC(channels) ||
3758 CHECK_CODEC(frame_size)) {
3759 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3763 http_log("Unknown codec type\n");
3771 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3772 feed->feed_filename, s->nb_streams, feed->nb_streams);
3774 avformat_close_input(&s);
3776 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3777 feed->feed_filename);
3780 if (feed->readonly) {
3781 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3782 feed->feed_filename);
3785 unlink(feed->feed_filename);
3788 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3789 AVFormatContext s1 = {0}, *s = &s1;
3791 if (feed->readonly) {
3792 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3793 feed->feed_filename);
3797 /* only write the header of the ffm file */
3798 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3799 http_log("Could not open output feed file '%s'\n",
3800 feed->feed_filename);
3803 s->oformat = feed->fmt;
3804 s->nb_streams = feed->nb_streams;
3805 s->streams = feed->streams;
3806 if (avformat_write_header(s, NULL) < 0) {
3807 http_log("Container doesn't support the required parameters\n");
3810 /* XXX: need better api */
3811 av_freep(&s->priv_data);
3814 /* get feed size and write index */
3815 fd = open(feed->feed_filename, O_RDONLY);
3817 http_log("Could not open output feed file '%s'\n",
3818 feed->feed_filename);
3822 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3823 feed->feed_size = lseek(fd, 0, SEEK_END);
3824 /* ensure that we do not wrap before the end of file */
3825 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3826 feed->feed_max_size = feed->feed_size;
3832 /* compute the bandwidth used by each stream */
3833 static void compute_bandwidth(void)
3839 for(stream = first_stream; stream != NULL; stream = stream->next) {
3841 for(i=0;i<stream->nb_streams;i++) {
3842 AVStream *st = stream->streams[i];
3843 switch(st->codec->codec_type) {
3844 case AVMEDIA_TYPE_AUDIO:
3845 case AVMEDIA_TYPE_VIDEO:
3846 bandwidth += st->codec->bit_rate;
3852 stream->bandwidth = (bandwidth + 999) / 1000;
3856 /* add a codec and set the default parameters */
3857 static void add_codec(FFStream *stream, AVCodecContext *av)
3861 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3864 /* compute default parameters */
3865 switch(av->codec_type) {
3866 case AVMEDIA_TYPE_AUDIO:
3867 if (av->bit_rate == 0)
3868 av->bit_rate = 64000;
3869 if (av->sample_rate == 0)
3870 av->sample_rate = 22050;
3871 if (av->channels == 0)
3874 case AVMEDIA_TYPE_VIDEO:
3875 if (av->bit_rate == 0)
3876 av->bit_rate = 64000;
3877 if (av->time_base.num == 0){
3878 av->time_base.den = 5;
3879 av->time_base.num = 1;
3881 if (av->width == 0 || av->height == 0) {
3885 /* Bitrate tolerance is less for streaming */
3886 if (av->bit_rate_tolerance == 0)
3887 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3888 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3893 if (av->max_qdiff == 0)
3895 av->qcompress = 0.5;
3898 if (!av->nsse_weight)
3899 av->nsse_weight = 8;
3901 av->frame_skip_cmp = FF_CMP_DCTMAX;
3903 av->me_method = ME_EPZS;
3904 av->rc_buffer_aggressivity = 1.0;
3907 av->rc_eq = "tex^qComp";
3908 if (!av->i_quant_factor)
3909 av->i_quant_factor = -0.8;
3910 if (!av->b_quant_factor)
3911 av->b_quant_factor = 1.25;
3912 if (!av->b_quant_offset)
3913 av->b_quant_offset = 1.25;
3914 if (!av->rc_max_rate)
3915 av->rc_max_rate = av->bit_rate * 2;
3917 if (av->rc_max_rate && !av->rc_buffer_size) {
3918 av->rc_buffer_size = av->rc_max_rate;
3927 st = av_mallocz(sizeof(AVStream));
3930 st->codec = avcodec_alloc_context3(NULL);
3931 stream->streams[stream->nb_streams++] = st;
3932 memcpy(st->codec, av, sizeof(AVCodecContext));
3935 static enum AVCodecID opt_audio_codec(const char *arg)
3937 AVCodec *p= avcodec_find_encoder_by_name(arg);
3939 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3940 return AV_CODEC_ID_NONE;
3945 static enum AVCodecID opt_video_codec(const char *arg)
3947 AVCodec *p= avcodec_find_encoder_by_name(arg);
3949 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3950 return AV_CODEC_ID_NONE;
3955 /* simplistic plugin support */
3958 static void load_module(const char *filename)
3961 void (*init_func)(void);
3962 dll = dlopen(filename, RTLD_NOW);
3964 fprintf(stderr, "Could not load module '%s' - %s\n",
3965 filename, dlerror());
3969 init_func = dlsym(dll, "ffserver_module_init");
3972 "%s: init function 'ffserver_module_init()' not found\n",
3981 static int ffserver_opt_default(const char *opt, const char *arg,
3982 AVCodecContext *avctx, int type)
3985 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3987 ret = av_opt_set(avctx, opt, arg, 0);
3991 static int ffserver_opt_preset(const char *arg,
3992 AVCodecContext *avctx, int type,
3993 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3996 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3998 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
4000 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
4001 codec ? codec->name : NULL))) {
4002 fprintf(stderr, "File for preset '%s' not found\n", arg);
4007 int e= fscanf(f, "%999[^\n]\n", line) - 1;
4008 if(line[0] == '#' && !e)
4010 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
4012 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
4016 if(!strcmp(tmp, "acodec")){
4017 *audio_id = opt_audio_codec(tmp2);
4018 }else if(!strcmp(tmp, "vcodec")){
4019 *video_id = opt_video_codec(tmp2);
4020 }else if(!strcmp(tmp, "scodec")){
4021 /* opt_subtitle_codec(tmp2); */
4022 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
4023 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4034 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4035 const char *mime_type)
4037 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4040 AVOutputFormat *stream_fmt;
4041 char stream_format_name[64];
4043 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4044 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4053 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4057 fprintf(stderr, "%s:%d: ", filename, line_num);
4058 vfprintf(stderr, fmt, vl);
4064 static int parse_ffconfig(const char *filename)
4071 int val, errors, line_num;
4072 FFStream **last_stream, *stream, *redirect;
4073 FFStream **last_feed, *feed, *s;
4074 AVCodecContext audio_enc, video_enc;
4075 enum AVCodecID audio_id, video_id;
4077 f = fopen(filename, "r");
4085 first_stream = NULL;
4086 last_stream = &first_stream;
4088 last_feed = &first_feed;
4092 audio_id = AV_CODEC_ID_NONE;
4093 video_id = AV_CODEC_ID_NONE;
4095 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4097 if (fgets(line, sizeof(line), f) == NULL)
4103 if (*p == '\0' || *p == '#')
4106 get_arg(cmd, sizeof(cmd), &p);
4108 if (!av_strcasecmp(cmd, "Port")) {
4109 get_arg(arg, sizeof(arg), &p);
4111 if (val < 1 || val > 65536) {
4112 ERROR("Invalid_port: %s\n", arg);
4114 my_http_addr.sin_port = htons(val);
4115 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4116 get_arg(arg, sizeof(arg), &p);
4117 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4118 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4120 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4121 // do nothing here, its the default now
4122 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4123 get_arg(arg, sizeof(arg), &p);
4125 if (val < 1 || val > 65536) {
4126 ERROR("%s:%d: Invalid port: %s\n", arg);
4128 my_rtsp_addr.sin_port = htons(atoi(arg));
4129 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4130 get_arg(arg, sizeof(arg), &p);
4131 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4132 ERROR("Invalid host/IP address: %s\n", arg);
4134 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4135 get_arg(arg, sizeof(arg), &p);
4137 if (val < 1 || val > 65536) {
4138 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4140 nb_max_http_connections = val;
4141 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4142 get_arg(arg, sizeof(arg), &p);
4144 if (val < 1 || val > nb_max_http_connections) {
4145 ERROR("Invalid MaxClients: %s\n", arg);
4147 nb_max_connections = val;
4149 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4151 get_arg(arg, sizeof(arg), &p);
4153 if (llval < 10 || llval > 10000000) {
4154 ERROR("Invalid MaxBandwidth: %s\n", arg);
4156 max_bandwidth = llval;
4157 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4158 if (!ffserver_debug)
4159 get_arg(logfilename, sizeof(logfilename), &p);
4160 } else if (!av_strcasecmp(cmd, "<Feed")) {
4161 /*********************************************/
4162 /* Feed related options */
4164 if (stream || feed) {
4165 ERROR("Already in a tag\n");
4167 feed = av_mallocz(sizeof(FFStream));
4168 get_arg(feed->filename, sizeof(feed->filename), &p);
4169 q = strrchr(feed->filename, '>');
4173 for (s = first_feed; s; s = s->next) {
4174 if (!strcmp(feed->filename, s->filename)) {
4175 ERROR("Feed '%s' already registered\n", s->filename);
4179 feed->fmt = av_guess_format("ffm", NULL, NULL);
4180 /* defaut feed file */
4181 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4182 "/tmp/%s.ffm", feed->filename);
4183 feed->feed_max_size = 5 * 1024 * 1024;
4185 feed->feed = feed; /* self feeding :-) */
4187 /* add in stream list */
4188 *last_stream = feed;
4189 last_stream = &feed->next;
4190 /* add in feed list */
4192 last_feed = &feed->next_feed;
4194 } else if (!av_strcasecmp(cmd, "Launch")) {
4198 feed->child_argv = av_mallocz(64 * sizeof(char *));
4200 for (i = 0; i < 62; i++) {
4201 get_arg(arg, sizeof(arg), &p);
4205 feed->child_argv[i] = av_strdup(arg);
4208 feed->child_argv[i] = av_asprintf("http://%s:%d/%s",
4209 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4210 inet_ntoa(my_http_addr.sin_addr),
4211 ntohs(my_http_addr.sin_port), feed->filename);
4213 } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
4215 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4217 } else if (stream) {
4218 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4220 } else if (!av_strcasecmp(cmd, "File")) {
4222 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4224 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4225 } else if (!av_strcasecmp(cmd, "Truncate")) {
4227 get_arg(arg, sizeof(arg), &p);
4228 feed->truncate = strtod(arg, NULL);
4230 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4235 get_arg(arg, sizeof(arg), &p);
4237 fsize = strtod(p1, &p1);
4238 switch(toupper(*p1)) {
4243 fsize *= 1024 * 1024;
4246 fsize *= 1024 * 1024 * 1024;
4249 feed->feed_max_size = (int64_t)fsize;
4250 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4251 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4254 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4256 ERROR("No corresponding <Feed> for </Feed>\n");
4259 } else if (!av_strcasecmp(cmd, "<Stream")) {
4260 /*********************************************/
4261 /* Stream related options */
4263 if (stream || feed) {
4264 ERROR("Already in a tag\n");
4267 stream = av_mallocz(sizeof(FFStream));
4268 get_arg(stream->filename, sizeof(stream->filename), &p);
4269 q = strrchr(stream->filename, '>');
4273 for (s = first_stream; s; s = s->next) {
4274 if (!strcmp(stream->filename, s->filename)) {
4275 ERROR("Stream '%s' already registered\n", s->filename);
4279 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4280 avcodec_get_context_defaults3(&video_enc, NULL);
4281 avcodec_get_context_defaults3(&audio_enc, NULL);
4283 audio_id = AV_CODEC_ID_NONE;
4284 video_id = AV_CODEC_ID_NONE;
4286 audio_id = stream->fmt->audio_codec;
4287 video_id = stream->fmt->video_codec;
4290 *last_stream = stream;
4291 last_stream = &stream->next;
4293 } else if (!av_strcasecmp(cmd, "Feed")) {
4294 get_arg(arg, sizeof(arg), &p);
4299 while (sfeed != NULL) {
4300 if (!strcmp(sfeed->filename, arg))
4302 sfeed = sfeed->next_feed;
4305 ERROR("feed '%s' not defined\n", arg);
4307 stream->feed = sfeed;
4309 } else if (!av_strcasecmp(cmd, "Format")) {
4310 get_arg(arg, sizeof(arg), &p);
4312 if (!strcmp(arg, "status")) {
4313 stream->stream_type = STREAM_TYPE_STATUS;
4316 stream->stream_type = STREAM_TYPE_LIVE;
4317 /* jpeg cannot be used here, so use single frame jpeg */
4318 if (!strcmp(arg, "jpeg"))
4319 strcpy(arg, "mjpeg");
4320 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4322 ERROR("Unknown Format: %s\n", arg);
4326 audio_id = stream->fmt->audio_codec;
4327 video_id = stream->fmt->video_codec;
4330 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4331 get_arg(arg, sizeof(arg), &p);
4333 stream->ifmt = av_find_input_format(arg);
4334 if (!stream->ifmt) {
4335 ERROR("Unknown input format: %s\n", arg);
4338 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4339 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4340 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4342 ERROR("FaviconURL only permitted for status streams\n");
4344 } else if (!av_strcasecmp(cmd, "Author")) {
4346 get_arg(stream->author, sizeof(stream->author), &p);
4347 } else if (!av_strcasecmp(cmd, "Comment")) {
4349 get_arg(stream->comment, sizeof(stream->comment), &p);
4350 } else if (!av_strcasecmp(cmd, "Copyright")) {
4352 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4353 } else if (!av_strcasecmp(cmd, "Title")) {
4355 get_arg(stream->title, sizeof(stream->title), &p);
4356 } else if (!av_strcasecmp(cmd, "Preroll")) {
4357 get_arg(arg, sizeof(arg), &p);
4359 stream->prebuffer = atof(arg) * 1000;
4360 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4362 stream->send_on_key = 1;
4363 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4364 get_arg(arg, sizeof(arg), &p);
4365 audio_id = opt_audio_codec(arg);
4366 if (audio_id == AV_CODEC_ID_NONE) {
4367 ERROR("Unknown AudioCodec: %s\n", arg);
4369 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4370 get_arg(arg, sizeof(arg), &p);
4371 video_id = opt_video_codec(arg);
4372 if (video_id == AV_CODEC_ID_NONE) {
4373 ERROR("Unknown VideoCodec: %s\n", arg);
4375 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4376 get_arg(arg, sizeof(arg), &p);
4378 stream->max_time = atof(arg) * 1000;
4379 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4380 get_arg(arg, sizeof(arg), &p);
4382 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4383 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4384 get_arg(arg, sizeof(arg), &p);
4386 audio_enc.channels = atoi(arg);
4387 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4388 get_arg(arg, sizeof(arg), &p);
4390 audio_enc.sample_rate = atoi(arg);
4391 } else if (!av_strcasecmp(cmd, "AudioQuality")) {
4392 get_arg(arg, sizeof(arg), &p);
4394 // audio_enc.quality = atof(arg) * 1000;
4396 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4398 int minrate, maxrate;
4400 get_arg(arg, sizeof(arg), &p);
4402 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4403 video_enc.rc_min_rate = minrate * 1000;
4404 video_enc.rc_max_rate = maxrate * 1000;
4406 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4409 } else if (!av_strcasecmp(cmd, "Debug")) {
4411 get_arg(arg, sizeof(arg), &p);
4412 video_enc.debug = strtol(arg,0,0);
4414 } else if (!av_strcasecmp(cmd, "Strict")) {
4416 get_arg(arg, sizeof(arg), &p);
4417 video_enc.strict_std_compliance = atoi(arg);
4419 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4421 get_arg(arg, sizeof(arg), &p);
4422 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4424 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4426 get_arg(arg, sizeof(arg), &p);
4427 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4429 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4430 get_arg(arg, sizeof(arg), &p);
4432 video_enc.bit_rate = atoi(arg) * 1000;
4434 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4435 get_arg(arg, sizeof(arg), &p);
4437 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4438 if ((video_enc.width % 16) != 0 ||
4439 (video_enc.height % 16) != 0) {
4440 ERROR("Image size must be a multiple of 16\n");
4443 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4444 get_arg(arg, sizeof(arg), &p);
4446 AVRational frame_rate;
4447 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4448 ERROR("Incorrect frame rate: %s\n", arg);
4450 video_enc.time_base.num = frame_rate.den;
4451 video_enc.time_base.den = frame_rate.num;
4454 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4455 get_arg(arg, sizeof(arg), &p);
4457 video_enc.gop_size = atoi(arg);
4458 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4460 video_enc.gop_size = 1;
4461 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4463 video_enc.mb_decision = FF_MB_DECISION_BITS;
4464 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4466 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4467 video_enc.flags |= CODEC_FLAG_4MV;
4469 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4470 !av_strcasecmp(cmd, "AVOptionAudio")) {
4472 AVCodecContext *avctx;
4474 get_arg(arg, sizeof(arg), &p);
4475 get_arg(arg2, sizeof(arg2), &p);
4476 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4478 type = AV_OPT_FLAG_VIDEO_PARAM;
4481 type = AV_OPT_FLAG_AUDIO_PARAM;
4483 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4484 ERROR("AVOption error: %s %s\n", arg, arg2);
4486 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4487 !av_strcasecmp(cmd, "AVPresetAudio")) {
4488 AVCodecContext *avctx;
4490 get_arg(arg, sizeof(arg), &p);
4491 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4493 video_enc.codec_id = video_id;
4494 type = AV_OPT_FLAG_VIDEO_PARAM;
4497 audio_enc.codec_id = audio_id;
4498 type = AV_OPT_FLAG_AUDIO_PARAM;
4500 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4501 ERROR("AVPreset error: %s\n", arg);
4503 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4504 get_arg(arg, sizeof(arg), &p);
4505 if ((strlen(arg) == 4) && stream)
4506 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4507 } else if (!av_strcasecmp(cmd, "BitExact")) {
4509 video_enc.flags |= CODEC_FLAG_BITEXACT;
4510 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4512 video_enc.dct_algo = FF_DCT_FASTINT;
4513 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4515 video_enc.idct_algo = FF_IDCT_SIMPLE;
4516 } else if (!av_strcasecmp(cmd, "Qscale")) {
4517 get_arg(arg, sizeof(arg), &p);
4519 video_enc.flags |= CODEC_FLAG_QSCALE;
4520 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4522 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4523 get_arg(arg, sizeof(arg), &p);
4525 video_enc.max_qdiff = atoi(arg);
4526 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4527 ERROR("VideoQDiff out of range\n");
4530 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4531 get_arg(arg, sizeof(arg), &p);
4533 video_enc.qmax = atoi(arg);
4534 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4535 ERROR("VideoQMax out of range\n");
4538 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4539 get_arg(arg, sizeof(arg), &p);
4541 video_enc.qmin = atoi(arg);
4542 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4543 ERROR("VideoQMin out of range\n");
4546 } else if (!av_strcasecmp(cmd, "LumaElim")) {
4547 get_arg(arg, sizeof(arg), &p);
4549 video_enc.luma_elim_threshold = atoi(arg);
4550 } else if (!av_strcasecmp(cmd, "ChromaElim")) {
4551 get_arg(arg, sizeof(arg), &p);
4553 video_enc.chroma_elim_threshold = atoi(arg);
4554 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4555 get_arg(arg, sizeof(arg), &p);
4557 video_enc.lumi_masking = atof(arg);
4558 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4559 get_arg(arg, sizeof(arg), &p);
4561 video_enc.dark_masking = atof(arg);
4562 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4563 video_id = AV_CODEC_ID_NONE;
4564 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4565 audio_id = AV_CODEC_ID_NONE;
4566 } else if (!av_strcasecmp(cmd, "ACL")) {
4567 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4568 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4570 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4572 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4573 get_arg(arg, sizeof(arg), &p);
4575 av_freep(&stream->rtsp_option);
4576 stream->rtsp_option = av_strdup(arg);
4578 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4579 get_arg(arg, sizeof(arg), &p);
4581 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4582 ERROR("Invalid host/IP address: %s\n", arg);
4584 stream->is_multicast = 1;
4585 stream->loop = 1; /* default is looping */
4587 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4588 get_arg(arg, sizeof(arg), &p);
4590 stream->multicast_port = atoi(arg);
4591 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4592 get_arg(arg, sizeof(arg), &p);
4594 stream->multicast_ttl = atoi(arg);
4595 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4598 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4600 ERROR("No corresponding <Stream> for </Stream>\n");
4602 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4603 if (audio_id != AV_CODEC_ID_NONE) {
4604 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4605 audio_enc.codec_id = audio_id;
4606 add_codec(stream, &audio_enc);
4608 if (video_id != AV_CODEC_ID_NONE) {
4609 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4610 video_enc.codec_id = video_id;
4611 add_codec(stream, &video_enc);
4616 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4617 /*********************************************/
4619 if (stream || feed || redirect) {
4620 ERROR("Already in a tag\n");
4622 redirect = av_mallocz(sizeof(FFStream));
4623 *last_stream = redirect;
4624 last_stream = &redirect->next;
4626 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4627 q = strrchr(redirect->filename, '>');
4630 redirect->stream_type = STREAM_TYPE_REDIRECT;
4632 } else if (!av_strcasecmp(cmd, "URL")) {
4634 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4635 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4637 ERROR("No corresponding <Redirect> for </Redirect>\n");
4639 if (!redirect->feed_filename[0]) {
4640 ERROR("No URL found for <Redirect>\n");
4644 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4645 get_arg(arg, sizeof(arg), &p);
4649 ERROR("Module support not compiled into this version: '%s'\n", arg);
4652 ERROR("Incorrect keyword: '%s'\n", cmd);
4664 static void handle_child_exit(int sig)
4669 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4672 for (feed = first_feed; feed; feed = feed->next) {
4673 if (feed->pid == pid) {
4674 int uptime = time(0) - feed->pid_start;
4677 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4680 /* Turn off any more restarts */
4681 feed->child_argv = 0;
4686 need_to_start_children = 1;
4689 static void opt_debug(void)
4692 logfilename[0] = '-';
4695 void show_help_default(const char *opt, const char *arg)
4697 printf("usage: ffserver [options]\n"
4698 "Hyper fast multi format Audio/Video streaming server\n");
4700 show_help_options(options, "Main options:", 0, 0, 0);
4703 static const OptionDef options[] = {
4704 #include "cmdutils_common_opts.h"
4705 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4706 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4707 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4711 int main(int argc, char **argv)
4713 struct sigaction sigact = { { 0 } };
4715 parse_loglevel(argc, argv, options);
4717 avformat_network_init();
4719 show_banner(argc, argv, options);
4721 my_program_name = argv[0];
4723 parse_options(NULL, argc, argv, options, NULL);
4725 unsetenv("http_proxy"); /* Kill the http_proxy */
4727 av_lfg_init(&random_state, av_get_random_seed());
4729 sigact.sa_handler = handle_child_exit;
4730 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4731 sigaction(SIGCHLD, &sigact, 0);
4733 if (parse_ffconfig(config_filename) < 0) {
4734 fprintf(stderr, "Incorrect config file - exiting.\n");
4738 /* open log file if needed */
4739 if (logfilename[0] != '\0') {
4740 if (!strcmp(logfilename, "-"))
4743 logfile = fopen(logfilename, "a");
4744 av_log_set_callback(http_av_log);
4747 build_file_streams();
4749 build_feed_streams();
4751 compute_bandwidth();
4754 signal(SIGPIPE, SIG_IGN);
4756 if (http_server() < 0) {
4757 http_log("Could not start server\n");