2 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * multiple format streaming server based on the FFmpeg libraries
28 #define closesocket close
33 #include "libavformat/avformat.h"
34 // FIXME those are internal headers, ffserver _really_ shouldn't use them
35 #include "libavformat/ffm.h"
36 #include "libavformat/network.h"
37 #include "libavformat/os_support.h"
38 #include "libavformat/rtpdec.h"
39 #include "libavformat/rtpproto.h"
40 #include "libavformat/rtsp.h"
41 #include "libavformat/rtspcodes.h"
42 #include "libavformat/avio_internal.h"
43 #include "libavformat/internal.h"
44 #include "libavformat/url.h"
46 #include "libavutil/avassert.h"
47 #include "libavutil/avstring.h"
48 #include "libavutil/lfg.h"
49 #include "libavutil/dict.h"
50 #include "libavutil/intreadwrite.h"
51 #include "libavutil/mathematics.h"
52 #include "libavutil/pixdesc.h"
53 #include "libavutil/random_seed.h"
54 #include "libavutil/parseutils.h"
55 #include "libavutil/opt.h"
56 #include "libavutil/time.h"
61 #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 AVDictionary *metadata; /* metadata to set on the stream */
221 AVInputFormat *ifmt; /* if non NULL, force input format */
224 char dynamic_acl[1024];
226 int prebuffer; /* Number of milliseconds early to start */
227 int64_t max_time; /* Number of milliseconds to run */
229 AVStream *streams[MAX_STREAMS];
230 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
231 char feed_filename[1024]; /* file name of the feed storage, or
232 input file name for a stream */
233 pid_t pid; /* Of ffmpeg process */
234 time_t pid_start; /* Of ffmpeg process */
236 struct FFStream *next;
237 unsigned bandwidth; /* bandwidth, in kbits/s */
240 /* multicast specific */
242 struct in_addr multicast_ip;
243 int multicast_port; /* first port used for multicast */
245 int loop; /* if true, send the stream in loops (only meaningful if file) */
248 int feed_opened; /* true if someone is writing to the feed */
249 int is_feed; /* true if it is a feed */
250 int readonly; /* True if writing is prohibited to the file */
251 int truncate; /* True if feeder connection truncate the feed file */
253 int64_t bytes_served;
254 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
255 int64_t feed_write_index; /* current write position in feed (it wraps around) */
256 int64_t feed_size; /* current size of feed */
257 struct FFStream *next_feed;
260 typedef struct FeedData {
261 long long data_count;
262 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
265 static struct sockaddr_in my_http_addr;
266 static struct sockaddr_in my_rtsp_addr;
268 static char logfilename[1024];
269 static HTTPContext *first_http_ctx;
270 static FFStream *first_feed; /* contains only feeds */
271 static FFStream *first_stream; /* contains all streams, including feeds */
273 static void new_connection(int server_fd, int is_rtsp);
274 static void close_connection(HTTPContext *c);
277 static int handle_connection(HTTPContext *c);
278 static int http_parse_request(HTTPContext *c);
279 static int http_send_data(HTTPContext *c);
280 static void compute_status(HTTPContext *c);
281 static int open_input_stream(HTTPContext *c, const char *info);
282 static int http_start_receive_data(HTTPContext *c);
283 static int http_receive_data(HTTPContext *c);
286 static int rtsp_parse_request(HTTPContext *c);
287 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
288 static void rtsp_cmd_options(HTTPContext *c, const char *url);
289 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
290 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
291 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only);
294 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
295 struct in_addr my_ip);
298 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
299 FFStream *stream, const char *session_id,
300 enum RTSPLowerTransport rtp_protocol);
301 static int rtp_new_av_stream(HTTPContext *c,
302 int stream_index, struct sockaddr_in *dest_addr,
303 HTTPContext *rtsp_c);
305 static const char *my_program_name;
307 static const char *config_filename;
309 static int ffserver_debug;
310 static int no_launch;
311 static int need_to_start_children;
313 /* maximum number of simultaneous HTTP connections */
314 static unsigned int nb_max_http_connections = 2000;
315 static unsigned int nb_max_connections = 5;
316 static unsigned int nb_connections;
318 static uint64_t max_bandwidth = 1000;
319 static uint64_t current_bandwidth;
321 static int64_t cur_time; // Making this global saves on passing it around everywhere
323 static AVLFG random_state;
325 static FILE *logfile = NULL;
327 static void htmlstrip(char *s) {
329 s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
335 static int64_t ffm_read_write_index(int fd)
339 if (lseek(fd, 8, SEEK_SET) < 0)
341 if (read(fd, buf, 8) != 8)
346 static int ffm_write_write_index(int fd, int64_t pos)
352 buf[i] = (pos >> (56 - i * 8)) & 0xff;
353 if (lseek(fd, 8, SEEK_SET) < 0)
355 if (write(fd, buf, 8) != 8)
360 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
363 FFMContext *ffm = s->priv_data;
364 ffm->write_index = pos;
365 ffm->file_size = file_size;
368 /* FIXME: make ffserver work with IPv6 */
369 /* resolve host with also IP address parsing */
370 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
373 if (!ff_inet_aton(hostname, sin_addr)) {
375 struct addrinfo *ai, *cur;
376 struct addrinfo hints = { 0 };
377 hints.ai_family = AF_INET;
378 if (getaddrinfo(hostname, NULL, &hints, &ai))
380 /* getaddrinfo returns a linked list of addrinfo structs.
381 * Even if we set ai_family = AF_INET above, make sure
382 * that the returned one actually is of the correct type. */
383 for (cur = ai; cur; cur = cur->ai_next) {
384 if (cur->ai_family == AF_INET) {
385 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
394 hp = gethostbyname(hostname);
397 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
403 static char *ctime1(char *buf2, int buf_size)
410 av_strlcpy(buf2, p, buf_size);
411 p = buf2 + strlen(p) - 1;
417 static void http_vlog(const char *fmt, va_list vargs)
419 static int print_prefix = 1;
423 ctime1(buf, sizeof(buf));
424 fprintf(logfile, "%s ", buf);
426 print_prefix = strstr(fmt, "\n") != NULL;
427 vfprintf(logfile, fmt, vargs);
433 __attribute__ ((format (printf, 1, 2)))
435 static void http_log(const char *fmt, ...)
438 va_start(vargs, fmt);
439 http_vlog(fmt, vargs);
443 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
445 static int print_prefix = 1;
446 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
447 if (level > av_log_get_level())
449 if (print_prefix && avc)
450 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
451 print_prefix = strstr(fmt, "\n") != NULL;
452 http_vlog(fmt, vargs);
455 static void log_connection(HTTPContext *c)
460 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
461 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
462 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
465 static void update_datarate(DataRateData *drd, int64_t count)
467 if (!drd->time1 && !drd->count1) {
468 drd->time1 = drd->time2 = cur_time;
469 drd->count1 = drd->count2 = count;
470 } else if (cur_time - drd->time2 > 5000) {
471 drd->time1 = drd->time2;
472 drd->count1 = drd->count2;
473 drd->time2 = cur_time;
478 /* In bytes per second */
479 static int compute_datarate(DataRateData *drd, int64_t count)
481 if (cur_time == drd->time1)
484 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
488 static void start_children(FFStream *feed)
493 for (; feed; feed = feed->next) {
494 if (feed->child_argv && !feed->pid) {
495 feed->pid_start = time(0);
500 http_log("Unable to create children\n");
509 /* replace "ffserver" with "ffmpeg" in the path of current
510 * program. Ignore user provided path */
511 av_strlcpy(pathname, my_program_name, sizeof(pathname));
512 slash = strrchr(pathname, '/');
517 strcpy(slash, "ffmpeg");
519 http_log("Launch command line: ");
520 http_log("%s ", pathname);
521 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
522 http_log("%s ", feed->child_argv[i]);
525 for (i = 3; i < 256; i++)
528 if (!ffserver_debug) {
529 if (!freopen("/dev/null", "r", stdin))
530 http_log("failed to redirect STDIN to /dev/null\n;");
531 if (!freopen("/dev/null", "w", stdout))
532 http_log("failed to redirect STDOUT to /dev/null\n;");
533 if (!freopen("/dev/null", "w", stderr))
534 http_log("failed to redirect STDERR to /dev/null\n;");
537 signal(SIGPIPE, SIG_DFL);
539 execvp(pathname, feed->child_argv);
547 /* open a listening socket */
548 static int socket_open_listen(struct sockaddr_in *my_addr)
552 server_fd = socket(AF_INET,SOCK_STREAM,0);
559 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
561 my_addr->sin_family = AF_INET;
562 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
564 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
566 closesocket(server_fd);
570 if (listen (server_fd, 5) < 0) {
572 closesocket(server_fd);
575 ff_socket_nonblock(server_fd, 1);
580 /* start all multicast streams */
581 static void start_multicast(void)
586 struct sockaddr_in dest_addr = {0};
587 int default_port, stream_index;
590 for(stream = first_stream; stream != NULL; stream = stream->next) {
591 if (stream->is_multicast) {
592 unsigned random0 = av_lfg_get(&random_state);
593 unsigned random1 = av_lfg_get(&random_state);
594 /* open the RTP connection */
595 snprintf(session_id, sizeof(session_id), "%08x%08x",
598 /* choose a port if none given */
599 if (stream->multicast_port == 0) {
600 stream->multicast_port = default_port;
604 dest_addr.sin_family = AF_INET;
605 dest_addr.sin_addr = stream->multicast_ip;
606 dest_addr.sin_port = htons(stream->multicast_port);
608 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
609 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
613 if (open_input_stream(rtp_c, "") < 0) {
614 http_log("Could not open input stream for stream '%s'\n",
619 /* open each RTP stream */
620 for(stream_index = 0; stream_index < stream->nb_streams;
622 dest_addr.sin_port = htons(stream->multicast_port +
624 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
625 http_log("Could not open output stream '%s/streamid=%d'\n",
626 stream->filename, stream_index);
631 rtp_c->state = HTTPSTATE_SEND_DATA;
636 /* main loop of the HTTP server */
637 static int http_server(void)
639 int server_fd = 0, rtsp_server_fd = 0;
641 struct pollfd *poll_table, *poll_entry;
642 HTTPContext *c, *c_next;
644 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
645 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
649 if (my_http_addr.sin_port) {
650 server_fd = socket_open_listen(&my_http_addr);
657 if (my_rtsp_addr.sin_port) {
658 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
659 if (rtsp_server_fd < 0) {
661 closesocket(server_fd);
666 if (!rtsp_server_fd && !server_fd) {
667 http_log("HTTP and RTSP disabled.\n");
672 http_log("FFserver started.\n");
674 start_children(first_feed);
679 poll_entry = poll_table;
681 poll_entry->fd = server_fd;
682 poll_entry->events = POLLIN;
685 if (rtsp_server_fd) {
686 poll_entry->fd = rtsp_server_fd;
687 poll_entry->events = POLLIN;
691 /* wait for events on each HTTP handle */
698 case HTTPSTATE_SEND_HEADER:
699 case RTSPSTATE_SEND_REPLY:
700 case RTSPSTATE_SEND_PACKET:
701 c->poll_entry = poll_entry;
703 poll_entry->events = POLLOUT;
706 case HTTPSTATE_SEND_DATA_HEADER:
707 case HTTPSTATE_SEND_DATA:
708 case HTTPSTATE_SEND_DATA_TRAILER:
709 if (!c->is_packetized) {
710 /* for TCP, we output as much as we can
711 * (may need to put a limit) */
712 c->poll_entry = poll_entry;
714 poll_entry->events = POLLOUT;
717 /* when ffserver is doing the timing, we work by
718 looking at which packet needs to be sent every
720 /* one tick wait XXX: 10 ms assumed */
725 case HTTPSTATE_WAIT_REQUEST:
726 case HTTPSTATE_RECEIVE_DATA:
727 case HTTPSTATE_WAIT_FEED:
728 case RTSPSTATE_WAIT_REQUEST:
729 /* need to catch errors */
730 c->poll_entry = poll_entry;
732 poll_entry->events = POLLIN;/* Maybe this will work */
736 c->poll_entry = NULL;
742 /* wait for an event on one connection. We poll at least every
743 second to handle timeouts */
745 ret = poll(poll_table, poll_entry - poll_table, delay);
746 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
747 ff_neterrno() != AVERROR(EINTR))
751 cur_time = av_gettime() / 1000;
753 if (need_to_start_children) {
754 need_to_start_children = 0;
755 start_children(first_feed);
758 /* now handle the events */
759 for(c = first_http_ctx; c != NULL; c = c_next) {
761 if (handle_connection(c) < 0) {
763 /* close and free the connection */
768 poll_entry = poll_table;
770 /* new HTTP connection request ? */
771 if (poll_entry->revents & POLLIN)
772 new_connection(server_fd, 0);
775 if (rtsp_server_fd) {
776 /* new RTSP connection request ? */
777 if (poll_entry->revents & POLLIN)
778 new_connection(rtsp_server_fd, 1);
783 /* start waiting for a new HTTP/RTSP request */
784 static void start_wait_request(HTTPContext *c, int is_rtsp)
786 c->buffer_ptr = c->buffer;
787 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
790 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
791 c->state = RTSPSTATE_WAIT_REQUEST;
793 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
794 c->state = HTTPSTATE_WAIT_REQUEST;
798 static void http_send_too_busy_reply(int fd)
801 int len = snprintf(buffer, sizeof(buffer),
802 "HTTP/1.0 503 Server too busy\r\n"
803 "Content-type: text/html\r\n"
805 "<html><head><title>Too busy</title></head><body>\r\n"
806 "<p>The server is too busy to serve your request at this time.</p>\r\n"
807 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
808 "</body></html>\r\n",
809 nb_connections, nb_max_connections);
810 av_assert0(len < sizeof(buffer));
811 send(fd, buffer, len, 0);
815 static void new_connection(int server_fd, int is_rtsp)
817 struct sockaddr_in from_addr;
820 HTTPContext *c = NULL;
822 len = sizeof(from_addr);
823 fd = accept(server_fd, (struct sockaddr *)&from_addr,
826 http_log("error during accept %s\n", strerror(errno));
829 ff_socket_nonblock(fd, 1);
831 if (nb_connections >= nb_max_connections) {
832 http_send_too_busy_reply(fd);
836 /* add a new connection */
837 c = av_mallocz(sizeof(HTTPContext));
842 c->poll_entry = NULL;
843 c->from_addr = from_addr;
844 c->buffer_size = IOBUFFER_INIT_SIZE;
845 c->buffer = av_malloc(c->buffer_size);
849 c->next = first_http_ctx;
853 start_wait_request(c, is_rtsp);
865 static void close_connection(HTTPContext *c)
867 HTTPContext **cp, *c1;
869 AVFormatContext *ctx;
873 /* remove connection from list */
874 cp = &first_http_ctx;
875 while ((*cp) != NULL) {
883 /* remove references, if any (XXX: do it faster) */
884 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
889 /* remove connection associated resources */
893 /* close each frame parser */
894 for(i=0;i<c->fmt_in->nb_streams;i++) {
895 st = c->fmt_in->streams[i];
896 if (st->codec->codec)
897 avcodec_close(st->codec);
899 avformat_close_input(&c->fmt_in);
902 /* free RTP output streams if any */
905 nb_streams = c->stream->nb_streams;
907 for(i=0;i<nb_streams;i++) {
910 av_write_trailer(ctx);
911 av_dict_free(&ctx->metadata);
912 av_free(ctx->streams[0]);
915 h = c->rtp_handles[i];
922 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
925 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
926 av_write_trailer(ctx);
927 av_freep(&c->pb_buffer);
928 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
933 for(i=0; i<ctx->nb_streams; i++)
934 av_free(ctx->streams[i]);
935 av_freep(&ctx->streams);
936 av_freep(&ctx->priv_data);
938 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
939 current_bandwidth -= c->stream->bandwidth;
941 /* signal that there is no feed if we are the feeder socket */
942 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
943 c->stream->feed_opened = 0;
947 av_freep(&c->pb_buffer);
948 av_freep(&c->packet_buffer);
954 static int handle_connection(HTTPContext *c)
959 case HTTPSTATE_WAIT_REQUEST:
960 case RTSPSTATE_WAIT_REQUEST:
962 if ((c->timeout - cur_time) < 0)
964 if (c->poll_entry->revents & (POLLERR | POLLHUP))
967 /* no need to read if no events */
968 if (!(c->poll_entry->revents & POLLIN))
972 len = recv(c->fd, c->buffer_ptr, 1, 0);
974 if (ff_neterrno() != AVERROR(EAGAIN) &&
975 ff_neterrno() != AVERROR(EINTR))
977 } else if (len == 0) {
980 /* search for end of request. */
982 c->buffer_ptr += len;
984 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
985 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
986 /* request found : parse it and reply */
987 if (c->state == HTTPSTATE_WAIT_REQUEST) {
988 ret = http_parse_request(c);
990 ret = rtsp_parse_request(c);
994 } else if (ptr >= c->buffer_end) {
995 /* request too long: cannot do anything */
997 } else goto read_loop;
1001 case HTTPSTATE_SEND_HEADER:
1002 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1005 /* no need to write if no events */
1006 if (!(c->poll_entry->revents & POLLOUT))
1008 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1010 if (ff_neterrno() != AVERROR(EAGAIN) &&
1011 ff_neterrno() != AVERROR(EINTR)) {
1012 goto close_connection;
1015 c->buffer_ptr += len;
1017 c->stream->bytes_served += len;
1018 c->data_count += len;
1019 if (c->buffer_ptr >= c->buffer_end) {
1020 av_freep(&c->pb_buffer);
1021 /* if error, exit */
1024 /* all the buffer was sent : synchronize to the incoming
1026 c->state = HTTPSTATE_SEND_DATA_HEADER;
1027 c->buffer_ptr = c->buffer_end = c->buffer;
1032 case HTTPSTATE_SEND_DATA:
1033 case HTTPSTATE_SEND_DATA_HEADER:
1034 case HTTPSTATE_SEND_DATA_TRAILER:
1035 /* for packetized output, we consider we can always write (the
1036 input streams set the speed). It may be better to verify
1037 that we do not rely too much on the kernel queues */
1038 if (!c->is_packetized) {
1039 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1042 /* no need to read if no events */
1043 if (!(c->poll_entry->revents & POLLOUT))
1046 if (http_send_data(c) < 0)
1048 /* close connection if trailer sent */
1049 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1052 case HTTPSTATE_RECEIVE_DATA:
1053 /* no need to read if no events */
1054 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1056 if (!(c->poll_entry->revents & POLLIN))
1058 if (http_receive_data(c) < 0)
1061 case HTTPSTATE_WAIT_FEED:
1062 /* no need to read if no events */
1063 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1066 /* nothing to do, we'll be waken up by incoming feed packets */
1069 case RTSPSTATE_SEND_REPLY:
1070 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1071 goto close_connection;
1072 /* no need to write if no events */
1073 if (!(c->poll_entry->revents & POLLOUT))
1075 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1077 if (ff_neterrno() != AVERROR(EAGAIN) &&
1078 ff_neterrno() != AVERROR(EINTR)) {
1079 goto close_connection;
1082 c->buffer_ptr += len;
1083 c->data_count += len;
1084 if (c->buffer_ptr >= c->buffer_end) {
1085 /* all the buffer was sent : wait for a new request */
1086 av_freep(&c->pb_buffer);
1087 start_wait_request(c, 1);
1091 case RTSPSTATE_SEND_PACKET:
1092 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1093 av_freep(&c->packet_buffer);
1096 /* no need to write if no events */
1097 if (!(c->poll_entry->revents & POLLOUT))
1099 len = send(c->fd, c->packet_buffer_ptr,
1100 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1102 if (ff_neterrno() != AVERROR(EAGAIN) &&
1103 ff_neterrno() != AVERROR(EINTR)) {
1104 /* error : close connection */
1105 av_freep(&c->packet_buffer);
1109 c->packet_buffer_ptr += len;
1110 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1111 /* all the buffer was sent : wait for a new request */
1112 av_freep(&c->packet_buffer);
1113 c->state = RTSPSTATE_WAIT_REQUEST;
1117 case HTTPSTATE_READY:
1126 av_freep(&c->pb_buffer);
1130 static int extract_rates(char *rates, int ratelen, const char *request)
1134 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1135 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1136 const char *q = p + 7;
1138 while (*q && *q != '\n' && av_isspace(*q))
1141 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1147 memset(rates, 0xff, ratelen);
1150 while (*q && *q != '\n' && *q != ':')
1153 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1157 if (stream_no < ratelen && stream_no >= 0)
1158 rates[stream_no] = rate_no;
1160 while (*q && *q != '\n' && !av_isspace(*q))
1167 p = strchr(p, '\n');
1177 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1180 int best_bitrate = 100000000;
1183 for (i = 0; i < feed->nb_streams; i++) {
1184 AVCodecContext *feed_codec = feed->streams[i]->codec;
1186 if (feed_codec->codec_id != codec->codec_id ||
1187 feed_codec->sample_rate != codec->sample_rate ||
1188 feed_codec->width != codec->width ||
1189 feed_codec->height != codec->height)
1192 /* Potential stream */
1194 /* We want the fastest stream less than bit_rate, or the slowest
1195 * faster than bit_rate
1198 if (feed_codec->bit_rate <= bit_rate) {
1199 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1200 best_bitrate = feed_codec->bit_rate;
1204 if (feed_codec->bit_rate < best_bitrate) {
1205 best_bitrate = feed_codec->bit_rate;
1214 static int modify_current_stream(HTTPContext *c, char *rates)
1217 FFStream *req = c->stream;
1218 int action_required = 0;
1220 /* Not much we can do for a feed */
1224 for (i = 0; i < req->nb_streams; i++) {
1225 AVCodecContext *codec = req->streams[i]->codec;
1229 c->switch_feed_streams[i] = req->feed_streams[i];
1232 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1235 /* Wants off or slow */
1236 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1238 /* This doesn't work well when it turns off the only stream! */
1239 c->switch_feed_streams[i] = -2;
1240 c->feed_streams[i] = -2;
1245 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1246 action_required = 1;
1249 return action_required;
1252 /* XXX: factorize in utils.c ? */
1253 /* XXX: take care with different space meaning */
1254 static void skip_spaces(const char **pp)
1258 while (*p == ' ' || *p == '\t')
1263 static void get_word(char *buf, int buf_size, const char **pp)
1271 while (!av_isspace(*p) && *p != '\0') {
1272 if ((q - buf) < buf_size - 1)
1281 static void get_arg(char *buf, int buf_size, const char **pp)
1288 while (av_isspace(*p)) p++;
1291 if (*p == '\"' || *p == '\'')
1303 if ((q - buf) < buf_size - 1)
1308 if (quote && *p == quote)
1313 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1314 const char *p, const char *filename, int line_num)
1320 get_arg(arg, sizeof(arg), &p);
1321 if (av_strcasecmp(arg, "allow") == 0)
1322 acl.action = IP_ALLOW;
1323 else if (av_strcasecmp(arg, "deny") == 0)
1324 acl.action = IP_DENY;
1326 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1327 filename, line_num, arg);
1331 get_arg(arg, sizeof(arg), &p);
1333 if (resolve_host(&acl.first, arg) != 0) {
1334 fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1335 filename, line_num, arg);
1338 acl.last = acl.first;
1340 get_arg(arg, sizeof(arg), &p);
1343 if (resolve_host(&acl.last, arg) != 0) {
1344 fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1345 filename, line_num, arg);
1351 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1352 IPAddressACL **naclp = 0;
1358 naclp = &stream->acl;
1364 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1365 filename, line_num);
1371 naclp = &(*naclp)->next;
1380 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1385 IPAddressACL *acl = NULL;
1389 f = fopen(stream->dynamic_acl, "r");
1391 perror(stream->dynamic_acl);
1395 acl = av_mallocz(sizeof(IPAddressACL));
1399 if (fgets(line, sizeof(line), f) == NULL)
1403 while (av_isspace(*p))
1405 if (*p == '\0' || *p == '#')
1407 get_arg(cmd, sizeof(cmd), &p);
1409 if (!av_strcasecmp(cmd, "ACL"))
1410 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1417 static void free_acl_list(IPAddressACL *in_acl)
1419 IPAddressACL *pacl,*pacl2;
1429 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1431 enum IPAddressAction last_action = IP_DENY;
1433 struct in_addr *src = &c->from_addr.sin_addr;
1434 unsigned long src_addr = src->s_addr;
1436 for (acl = in_acl; acl; acl = acl->next) {
1437 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1438 return (acl->action == IP_ALLOW) ? 1 : 0;
1439 last_action = acl->action;
1442 /* Nothing matched, so return not the last action */
1443 return (last_action == IP_DENY) ? 1 : 0;
1446 static int validate_acl(FFStream *stream, HTTPContext *c)
1452 /* if stream->acl is null validate_acl_list will return 1 */
1453 ret = validate_acl_list(stream->acl, c);
1455 if (stream->dynamic_acl[0]) {
1456 acl = parse_dynamic_acl(stream, c);
1458 ret = validate_acl_list(acl, c);
1466 /* compute the real filename of a file by matching it without its
1467 extensions to all the stream's filenames */
1468 static void compute_real_filename(char *filename, int max_size)
1475 /* compute filename by matching without the file extensions */
1476 av_strlcpy(file1, filename, sizeof(file1));
1477 p = strrchr(file1, '.');
1480 for(stream = first_stream; stream != NULL; stream = stream->next) {
1481 av_strlcpy(file2, stream->filename, sizeof(file2));
1482 p = strrchr(file2, '.');
1485 if (!strcmp(file1, file2)) {
1486 av_strlcpy(filename, stream->filename, max_size);
1501 /* parse HTTP request and prepare header */
1502 static int http_parse_request(HTTPContext *c)
1506 enum RedirType redir_type;
1508 char info[1024], filename[1024];
1512 const char *mime_type;
1516 const char *useragent = 0;
1519 get_word(cmd, sizeof(cmd), &p);
1520 av_strlcpy(c->method, cmd, sizeof(c->method));
1522 if (!strcmp(cmd, "GET"))
1524 else if (!strcmp(cmd, "POST"))
1529 get_word(url, sizeof(url), &p);
1530 av_strlcpy(c->url, url, sizeof(c->url));
1532 get_word(protocol, sizeof(protocol), (const char **)&p);
1533 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1536 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1539 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1541 /* find the filename and the optional info string in the request */
1542 p1 = strchr(url, '?');
1544 av_strlcpy(info, p1, sizeof(info));
1549 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1551 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1552 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1554 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1558 p = strchr(p, '\n');
1565 redir_type = REDIR_NONE;
1566 if (av_match_ext(filename, "asx")) {
1567 redir_type = REDIR_ASX;
1568 filename[strlen(filename)-1] = 'f';
1569 } else if (av_match_ext(filename, "asf") &&
1570 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1571 /* if this isn't WMP or lookalike, return the redirector file */
1572 redir_type = REDIR_ASF;
1573 } else if (av_match_ext(filename, "rpm,ram")) {
1574 redir_type = REDIR_RAM;
1575 strcpy(filename + strlen(filename)-2, "m");
1576 } else if (av_match_ext(filename, "rtsp")) {
1577 redir_type = REDIR_RTSP;
1578 compute_real_filename(filename, sizeof(filename) - 1);
1579 } else if (av_match_ext(filename, "sdp")) {
1580 redir_type = REDIR_SDP;
1581 compute_real_filename(filename, sizeof(filename) - 1);
1584 // "redirect" / request to index.html
1585 if (!strlen(filename))
1586 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1588 stream = first_stream;
1589 while (stream != NULL) {
1590 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1592 stream = stream->next;
1594 if (stream == NULL) {
1595 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1596 http_log("File '%s' not found\n", url);
1601 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1602 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1604 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1605 c->http_error = 301;
1607 snprintf(q, c->buffer_size,
1608 "HTTP/1.0 301 Moved\r\n"
1610 "Content-type: text/html\r\n"
1612 "<html><head><title>Moved</title></head><body>\r\n"
1613 "You should be <a href=\"%s\">redirected</a>.\r\n"
1614 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1616 /* prepare output buffer */
1617 c->buffer_ptr = c->buffer;
1619 c->state = HTTPSTATE_SEND_HEADER;
1623 /* If this is WMP, get the rate information */
1624 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1625 if (modify_current_stream(c, ratebuf)) {
1626 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1627 if (c->switch_feed_streams[i] >= 0)
1628 c->switch_feed_streams[i] = -1;
1633 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1634 current_bandwidth += stream->bandwidth;
1636 /* If already streaming this feed, do not let start another feeder. */
1637 if (stream->feed_opened) {
1638 snprintf(msg, sizeof(msg), "This feed is already being received.");
1639 http_log("Feed '%s' already being received\n", stream->feed_filename);
1643 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1644 c->http_error = 503;
1646 snprintf(q, c->buffer_size,
1647 "HTTP/1.0 503 Server too busy\r\n"
1648 "Content-type: text/html\r\n"
1650 "<html><head><title>Too busy</title></head><body>\r\n"
1651 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1652 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1653 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1654 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1656 /* prepare output buffer */
1657 c->buffer_ptr = c->buffer;
1659 c->state = HTTPSTATE_SEND_HEADER;
1663 if (redir_type != REDIR_NONE) {
1664 const char *hostinfo = 0;
1666 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1667 if (av_strncasecmp(p, "Host:", 5) == 0) {
1671 p = strchr(p, '\n');
1682 while (av_isspace(*hostinfo))
1685 eoh = strchr(hostinfo, '\n');
1687 if (eoh[-1] == '\r')
1690 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1691 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1692 hostbuf[eoh - hostinfo] = 0;
1694 c->http_error = 200;
1696 switch(redir_type) {
1698 snprintf(q, c->buffer_size,
1699 "HTTP/1.0 200 ASX Follows\r\n"
1700 "Content-type: video/x-ms-asf\r\n"
1702 "<ASX Version=\"3\">\r\n"
1703 //"<!-- Autogenerated by ffserver -->\r\n"
1704 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1705 "</ASX>\r\n", hostbuf, filename, info);
1709 snprintf(q, c->buffer_size,
1710 "HTTP/1.0 200 RAM Follows\r\n"
1711 "Content-type: audio/x-pn-realaudio\r\n"
1713 "# Autogenerated by ffserver\r\n"
1714 "http://%s/%s%s\r\n", hostbuf, filename, info);
1718 snprintf(q, c->buffer_size,
1719 "HTTP/1.0 200 ASF Redirect follows\r\n"
1720 "Content-type: video/x-ms-asf\r\n"
1723 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1728 char hostname[256], *p;
1729 /* extract only hostname */
1730 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1731 p = strrchr(hostname, ':');
1734 snprintf(q, c->buffer_size,
1735 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1736 /* XXX: incorrect MIME type ? */
1737 "Content-type: application/x-rtsp\r\n"
1739 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1748 struct sockaddr_in my_addr;
1750 snprintf(q, c->buffer_size,
1751 "HTTP/1.0 200 OK\r\n"
1752 "Content-type: application/sdp\r\n"
1756 len = sizeof(my_addr);
1757 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1759 /* XXX: should use a dynamic buffer */
1760 sdp_data_size = prepare_sdp_description(stream,
1763 if (sdp_data_size > 0) {
1764 memcpy(q, sdp_data, sdp_data_size);
1776 /* prepare output buffer */
1777 c->buffer_ptr = c->buffer;
1779 c->state = HTTPSTATE_SEND_HEADER;
1785 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1789 stream->conns_served++;
1791 /* XXX: add there authenticate and IP match */
1794 /* if post, it means a feed is being sent */
1795 if (!stream->is_feed) {
1796 /* However it might be a status report from WMP! Let us log the
1797 * data as it might come handy one day. */
1798 const char *logline = 0;
1801 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1802 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1806 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1807 client_id = strtol(p + 18, 0, 10);
1808 p = strchr(p, '\n');
1816 char *eol = strchr(logline, '\n');
1821 if (eol[-1] == '\r')
1823 http_log("%.*s\n", (int) (eol - logline), logline);
1824 c->suppress_log = 1;
1829 http_log("\nGot request:\n%s\n", c->buffer);
1832 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1835 /* Now we have to find the client_id */
1836 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1837 if (wmpc->wmp_client_id == client_id)
1841 if (wmpc && modify_current_stream(wmpc, ratebuf))
1842 wmpc->switch_pending = 1;
1845 snprintf(msg, sizeof(msg), "POST command not handled");
1849 if (http_start_receive_data(c) < 0) {
1850 snprintf(msg, sizeof(msg), "could not open feed");
1854 c->state = HTTPSTATE_RECEIVE_DATA;
1859 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1860 http_log("\nGot request:\n%s\n", c->buffer);
1863 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1866 /* open input stream */
1867 if (open_input_stream(c, info) < 0) {
1868 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1872 /* prepare HTTP header */
1874 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1875 mime_type = c->stream->fmt->mime_type;
1877 mime_type = "application/x-octet-stream";
1878 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1880 /* for asf, we need extra headers */
1881 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1882 /* Need to allocate a client id */
1884 c->wmp_client_id = av_lfg_get(&random_state);
1886 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);
1888 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1889 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1890 q = c->buffer + strlen(c->buffer);
1892 /* prepare output buffer */
1894 c->buffer_ptr = c->buffer;
1896 c->state = HTTPSTATE_SEND_HEADER;
1899 c->http_error = 404;
1902 snprintf(q, c->buffer_size,
1903 "HTTP/1.0 404 Not Found\r\n"
1904 "Content-type: text/html\r\n"
1907 "<head><title>404 Not Found</title></head>\n"
1911 /* prepare output buffer */
1912 c->buffer_ptr = c->buffer;
1914 c->state = HTTPSTATE_SEND_HEADER;
1918 c->http_error = 200; /* horrible : we use this value to avoid
1919 going to the send data state */
1920 c->state = HTTPSTATE_SEND_HEADER;
1924 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1926 static const char suffix[] = " kMGTP";
1929 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1931 avio_printf(pb, "%"PRId64"%c", count, *s);
1934 static void compute_status(HTTPContext *c)
1943 if (avio_open_dyn_buf(&pb) < 0) {
1944 /* XXX: return an error ? */
1945 c->buffer_ptr = c->buffer;
1946 c->buffer_end = c->buffer;
1950 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1951 avio_printf(pb, "Content-type: text/html\r\n");
1952 avio_printf(pb, "Pragma: no-cache\r\n");
1953 avio_printf(pb, "\r\n");
1955 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1956 if (c->stream->feed_filename[0])
1957 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1958 avio_printf(pb, "</head>\n<body>");
1959 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1961 avio_printf(pb, "<h2>Available Streams</h2>\n");
1962 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1963 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");
1964 stream = first_stream;
1965 while (stream != NULL) {
1966 char sfilename[1024];
1969 if (stream->feed != stream) {
1970 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1971 eosf = sfilename + strlen(sfilename);
1972 if (eosf - sfilename >= 4) {
1973 if (strcmp(eosf - 4, ".asf") == 0)
1974 strcpy(eosf - 4, ".asx");
1975 else if (strcmp(eosf - 3, ".rm") == 0)
1976 strcpy(eosf - 3, ".ram");
1977 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1978 /* generate a sample RTSP director if
1979 unicast. Generate an SDP redirector if
1981 eosf = strrchr(sfilename, '.');
1983 eosf = sfilename + strlen(sfilename);
1984 if (stream->is_multicast)
1985 strcpy(eosf, ".sdp");
1987 strcpy(eosf, ".rtsp");
1991 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1992 sfilename, stream->filename);
1993 avio_printf(pb, "<td align=right> %d <td align=right> ",
1994 stream->conns_served);
1995 fmt_bytecount(pb, stream->bytes_served);
1996 switch(stream->stream_type) {
1997 case STREAM_TYPE_LIVE: {
1998 int audio_bit_rate = 0;
1999 int video_bit_rate = 0;
2000 const char *audio_codec_name = "";
2001 const char *video_codec_name = "";
2002 const char *audio_codec_name_extra = "";
2003 const char *video_codec_name_extra = "";
2005 for(i=0;i<stream->nb_streams;i++) {
2006 AVStream *st = stream->streams[i];
2007 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2008 switch(st->codec->codec_type) {
2009 case AVMEDIA_TYPE_AUDIO:
2010 audio_bit_rate += st->codec->bit_rate;
2012 if (*audio_codec_name)
2013 audio_codec_name_extra = "...";
2014 audio_codec_name = codec->name;
2017 case AVMEDIA_TYPE_VIDEO:
2018 video_bit_rate += st->codec->bit_rate;
2020 if (*video_codec_name)
2021 video_codec_name_extra = "...";
2022 video_codec_name = codec->name;
2025 case AVMEDIA_TYPE_DATA:
2026 video_bit_rate += st->codec->bit_rate;
2032 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",
2035 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2036 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2038 avio_printf(pb, "<td>%s", stream->feed->filename);
2040 avio_printf(pb, "<td>%s", stream->feed_filename);
2041 avio_printf(pb, "\n");
2045 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2049 stream = stream->next;
2051 avio_printf(pb, "</table>\n");
2053 stream = first_stream;
2054 while (stream != NULL) {
2055 if (stream->feed == stream) {
2056 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2058 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2065 /* This is somewhat linux specific I guess */
2066 snprintf(ps_cmd, sizeof(ps_cmd),
2067 "ps -o \"%%cpu,cputime\" --no-headers %d",
2070 pid_stat = popen(ps_cmd, "r");
2075 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2077 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2085 avio_printf(pb, "<p>");
2087 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");
2089 for (i = 0; i < stream->nb_streams; i++) {
2090 AVStream *st = stream->streams[i];
2091 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2092 const char *type = "unknown";
2093 char parameters[64];
2097 switch(st->codec->codec_type) {
2098 case AVMEDIA_TYPE_AUDIO:
2100 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2102 case AVMEDIA_TYPE_VIDEO:
2104 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2105 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2110 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2111 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2113 avio_printf(pb, "</table>\n");
2116 stream = stream->next;
2119 /* connection status */
2120 avio_printf(pb, "<h2>Connection Status</h2>\n");
2122 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2123 nb_connections, nb_max_connections);
2125 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2126 current_bandwidth, max_bandwidth);
2128 avio_printf(pb, "<table>\n");
2129 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");
2130 c1 = first_http_ctx;
2132 while (c1 != NULL) {
2138 for (j = 0; j < c1->stream->nb_streams; j++) {
2139 if (!c1->stream->feed)
2140 bitrate += c1->stream->streams[j]->codec->bit_rate;
2141 else if (c1->feed_streams[j] >= 0)
2142 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2147 p = inet_ntoa(c1->from_addr.sin_addr);
2148 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2150 c1->stream ? c1->stream->filename : "",
2151 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2154 http_state[c1->state]);
2155 fmt_bytecount(pb, bitrate);
2156 avio_printf(pb, "<td align=right>");
2157 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2158 avio_printf(pb, "<td align=right>");
2159 fmt_bytecount(pb, c1->data_count);
2160 avio_printf(pb, "\n");
2163 avio_printf(pb, "</table>\n");
2168 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2169 avio_printf(pb, "</body>\n</html>\n");
2171 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2172 c->buffer_ptr = c->pb_buffer;
2173 c->buffer_end = c->pb_buffer + len;
2176 static int open_input_stream(HTTPContext *c, const char *info)
2179 char input_filename[1024];
2180 AVFormatContext *s = NULL;
2181 int buf_size, i, ret;
2184 /* find file name */
2185 if (c->stream->feed) {
2186 strcpy(input_filename, c->stream->feed->feed_filename);
2187 buf_size = FFM_PACKET_SIZE;
2188 /* compute position (absolute time) */
2189 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2190 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2191 http_log("Invalid date specification '%s' for stream\n", buf);
2194 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2195 int prebuffer = strtol(buf, 0, 10);
2196 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2198 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2200 strcpy(input_filename, c->stream->feed_filename);
2202 /* compute position (relative time) */
2203 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2204 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2205 http_log("Invalid date specification '%s' for stream\n", buf);
2211 if (!input_filename[0]) {
2212 http_log("No filename was specified for stream\n");
2213 return AVERROR(EINVAL);
2217 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2218 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2222 /* set buffer size */
2223 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2225 s->flags |= AVFMT_FLAG_GENPTS;
2227 if (strcmp(s->iformat->name, "ffm") &&
2228 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2229 http_log("Could not find stream info for input '%s'\n", input_filename);
2230 avformat_close_input(&s);
2234 /* choose stream as clock source (we favor the video stream if
2235 * present) for packet sending */
2236 c->pts_stream_index = 0;
2237 for(i=0;i<c->stream->nb_streams;i++) {
2238 if (c->pts_stream_index == 0 &&
2239 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2240 c->pts_stream_index = i;
2244 if (c->fmt_in->iformat->read_seek)
2245 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2246 /* set the start time (needed for maxtime and RTP packet timing) */
2247 c->start_time = cur_time;
2248 c->first_pts = AV_NOPTS_VALUE;
2252 /* return the server clock (in us) */
2253 static int64_t get_server_clock(HTTPContext *c)
2255 /* compute current pts value from system time */
2256 return (cur_time - c->start_time) * 1000;
2259 /* return the estimated time at which the current packet must be sent
2261 static int64_t get_packet_send_clock(HTTPContext *c)
2263 int bytes_left, bytes_sent, frame_bytes;
2265 frame_bytes = c->cur_frame_bytes;
2266 if (frame_bytes <= 0)
2269 bytes_left = c->buffer_end - c->buffer_ptr;
2270 bytes_sent = frame_bytes - bytes_left;
2271 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2276 static int http_prepare_data(HTTPContext *c)
2279 AVFormatContext *ctx;
2281 av_freep(&c->pb_buffer);
2283 case HTTPSTATE_SEND_DATA_HEADER:
2284 ctx = avformat_alloc_context();
2287 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2288 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2290 for(i=0;i<c->stream->nb_streams;i++) {
2292 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2293 /* if file or feed, then just take streams from FFStream struct */
2294 if (!c->stream->feed ||
2295 c->stream->feed == c->stream)
2296 src = c->stream->streams[i];
2298 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2300 *(c->fmt_ctx.streams[i]) = *src;
2301 c->fmt_ctx.streams[i]->priv_data = 0;
2302 /* XXX: should be done in AVStream, not in codec */
2303 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2305 /* set output format parameters */
2306 c->fmt_ctx.oformat = c->stream->fmt;
2307 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2309 c->got_key_frame = 0;
2311 /* prepare header and save header data in a stream */
2312 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2313 /* XXX: potential leak */
2316 c->fmt_ctx.pb->seekable = 0;
2319 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2320 * Default value from FFmpeg
2321 * Try to set it using configuration option
2323 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2325 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2326 http_log("Error writing output header for stream '%s': %s\n",
2327 c->stream->filename, av_err2str(ret));
2330 av_dict_free(&c->fmt_ctx.metadata);
2332 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2333 c->buffer_ptr = c->pb_buffer;
2334 c->buffer_end = c->pb_buffer + len;
2336 c->state = HTTPSTATE_SEND_DATA;
2337 c->last_packet_sent = 0;
2339 case HTTPSTATE_SEND_DATA:
2340 /* find a new packet */
2341 /* read a packet from the input stream */
2342 if (c->stream->feed)
2343 ffm_set_write_index(c->fmt_in,
2344 c->stream->feed->feed_write_index,
2345 c->stream->feed->feed_size);
2347 if (c->stream->max_time &&
2348 c->stream->max_time + c->start_time - cur_time < 0)
2349 /* We have timed out */
2350 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2354 ret = av_read_frame(c->fmt_in, &pkt);
2356 if (c->stream->feed) {
2357 /* if coming from feed, it means we reached the end of the
2358 ffm file, so must wait for more data */
2359 c->state = HTTPSTATE_WAIT_FEED;
2360 return 1; /* state changed */
2361 } else if (ret == AVERROR(EAGAIN)) {
2362 /* input not ready, come back later */
2365 if (c->stream->loop) {
2366 avformat_close_input(&c->fmt_in);
2367 if (open_input_stream(c, "") < 0)
2372 /* must send trailer now because EOF or error */
2373 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2377 int source_index = pkt.stream_index;
2378 /* update first pts if needed */
2379 if (c->first_pts == AV_NOPTS_VALUE) {
2380 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2381 c->start_time = cur_time;
2383 /* send it to the appropriate stream */
2384 if (c->stream->feed) {
2385 /* if coming from a feed, select the right stream */
2386 if (c->switch_pending) {
2387 c->switch_pending = 0;
2388 for(i=0;i<c->stream->nb_streams;i++) {
2389 if (c->switch_feed_streams[i] == pkt.stream_index)
2390 if (pkt.flags & AV_PKT_FLAG_KEY)
2391 c->switch_feed_streams[i] = -1;
2392 if (c->switch_feed_streams[i] >= 0)
2393 c->switch_pending = 1;
2396 for(i=0;i<c->stream->nb_streams;i++) {
2397 if (c->stream->feed_streams[i] == pkt.stream_index) {
2398 AVStream *st = c->fmt_in->streams[source_index];
2399 pkt.stream_index = i;
2400 if (pkt.flags & AV_PKT_FLAG_KEY &&
2401 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2402 c->stream->nb_streams == 1))
2403 c->got_key_frame = 1;
2404 if (!c->stream->send_on_key || c->got_key_frame)
2409 AVCodecContext *codec;
2410 AVStream *ist, *ost;
2412 ist = c->fmt_in->streams[source_index];
2413 /* specific handling for RTP: we use several
2414 * output streams (one for each RTP connection).
2415 * XXX: need more abstract handling */
2416 if (c->is_packetized) {
2417 /* compute send time and duration */
2418 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2419 c->cur_pts -= c->first_pts;
2420 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2421 /* find RTP context */
2422 c->packet_stream_index = pkt.stream_index;
2423 ctx = c->rtp_ctx[c->packet_stream_index];
2425 av_free_packet(&pkt);
2428 codec = ctx->streams[0]->codec;
2429 /* only one stream per RTP connection */
2430 pkt.stream_index = 0;
2434 codec = ctx->streams[pkt.stream_index]->codec;
2437 if (c->is_packetized) {
2438 int max_packet_size;
2439 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2440 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2442 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2443 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2445 ret = avio_open_dyn_buf(&ctx->pb);
2448 /* XXX: potential leak */
2451 ost = ctx->streams[pkt.stream_index];
2453 ctx->pb->seekable = 0;
2454 if (pkt.dts != AV_NOPTS_VALUE)
2455 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2456 if (pkt.pts != AV_NOPTS_VALUE)
2457 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2458 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2459 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2460 http_log("Error writing frame to output for stream '%s': %s\n",
2461 c->stream->filename, av_err2str(ret));
2462 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2465 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2466 c->cur_frame_bytes = len;
2467 c->buffer_ptr = c->pb_buffer;
2468 c->buffer_end = c->pb_buffer + len;
2470 codec->frame_number++;
2472 av_free_packet(&pkt);
2476 av_free_packet(&pkt);
2481 case HTTPSTATE_SEND_DATA_TRAILER:
2482 /* last packet test ? */
2483 if (c->last_packet_sent || c->is_packetized)
2486 /* prepare header */
2487 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2488 /* XXX: potential leak */
2491 c->fmt_ctx.pb->seekable = 0;
2492 av_write_trailer(ctx);
2493 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2494 c->buffer_ptr = c->pb_buffer;
2495 c->buffer_end = c->pb_buffer + len;
2497 c->last_packet_sent = 1;
2503 /* should convert the format at the same time */
2504 /* send data starting at c->buffer_ptr to the output connection
2505 * (either UDP or TCP) */
2506 static int http_send_data(HTTPContext *c)
2511 if (c->buffer_ptr >= c->buffer_end) {
2512 ret = http_prepare_data(c);
2516 /* state change requested */
2519 if (c->is_packetized) {
2520 /* RTP data output */
2521 len = c->buffer_end - c->buffer_ptr;
2523 /* fail safe - should never happen */
2525 c->buffer_ptr = c->buffer_end;
2528 len = (c->buffer_ptr[0] << 24) |
2529 (c->buffer_ptr[1] << 16) |
2530 (c->buffer_ptr[2] << 8) |
2532 if (len > (c->buffer_end - c->buffer_ptr))
2534 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2535 /* nothing to send yet: we can wait */
2539 c->data_count += len;
2540 update_datarate(&c->datarate, c->data_count);
2542 c->stream->bytes_served += len;
2544 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2545 /* RTP packets are sent inside the RTSP TCP connection */
2547 int interleaved_index, size;
2549 HTTPContext *rtsp_c;
2552 /* if no RTSP connection left, error */
2555 /* if already sending something, then wait. */
2556 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2558 if (avio_open_dyn_buf(&pb) < 0)
2560 interleaved_index = c->packet_stream_index * 2;
2561 /* RTCP packets are sent at odd indexes */
2562 if (c->buffer_ptr[1] == 200)
2563 interleaved_index++;
2564 /* write RTSP TCP header */
2566 header[1] = interleaved_index;
2567 header[2] = len >> 8;
2569 avio_write(pb, header, 4);
2570 /* write RTP packet data */
2572 avio_write(pb, c->buffer_ptr, len);
2573 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2574 /* prepare asynchronous TCP sending */
2575 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2576 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2577 c->buffer_ptr += len;
2579 /* send everything we can NOW */
2580 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2581 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2583 rtsp_c->packet_buffer_ptr += len;
2584 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2585 /* if we could not send all the data, we will
2586 send it later, so a new state is needed to
2587 "lock" the RTSP TCP connection */
2588 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2591 /* all data has been sent */
2592 av_freep(&c->packet_buffer);
2594 /* send RTP packet directly in UDP */
2596 ffurl_write(c->rtp_handles[c->packet_stream_index],
2597 c->buffer_ptr, len);
2598 c->buffer_ptr += len;
2599 /* here we continue as we can send several packets per 10 ms slot */
2602 /* TCP data output */
2603 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2605 if (ff_neterrno() != AVERROR(EAGAIN) &&
2606 ff_neterrno() != AVERROR(EINTR))
2607 /* error : close connection */
2612 c->buffer_ptr += len;
2614 c->data_count += len;
2615 update_datarate(&c->datarate, c->data_count);
2617 c->stream->bytes_served += len;
2625 static int http_start_receive_data(HTTPContext *c)
2630 if (c->stream->feed_opened) {
2631 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2632 return AVERROR(EINVAL);
2635 /* Don't permit writing to this one */
2636 if (c->stream->readonly) {
2637 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2638 return AVERROR(EINVAL);
2642 fd = open(c->stream->feed_filename, O_RDWR);
2644 ret = AVERROR(errno);
2645 http_log("Could not open feed file '%s': %s\n",
2646 c->stream->feed_filename, strerror(errno));
2651 if (c->stream->truncate) {
2652 /* truncate feed file */
2653 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2654 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2655 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2656 ret = AVERROR(errno);
2657 http_log("Error truncating feed file '%s': %s\n",
2658 c->stream->feed_filename, strerror(errno));
2662 ret = ffm_read_write_index(fd);
2664 http_log("Error reading write index from feed file '%s': %s\n",
2665 c->stream->feed_filename, strerror(errno));
2668 c->stream->feed_write_index = ret;
2672 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2673 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2674 lseek(fd, 0, SEEK_SET);
2676 /* init buffer input */
2677 c->buffer_ptr = c->buffer;
2678 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2679 c->stream->feed_opened = 1;
2680 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2684 static int http_receive_data(HTTPContext *c)
2687 int len, loop_run = 0;
2689 while (c->chunked_encoding && !c->chunk_size &&
2690 c->buffer_end > c->buffer_ptr) {
2691 /* read chunk header, if present */
2692 len = recv(c->fd, c->buffer_ptr, 1, 0);
2695 if (ff_neterrno() != AVERROR(EAGAIN) &&
2696 ff_neterrno() != AVERROR(EINTR))
2697 /* error : close connection */
2700 } else if (len == 0) {
2701 /* end of connection : close it */
2703 } else if (c->buffer_ptr - c->buffer >= 2 &&
2704 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2705 c->chunk_size = strtol(c->buffer, 0, 16);
2706 if (c->chunk_size == 0) // end of stream
2708 c->buffer_ptr = c->buffer;
2710 } else if (++loop_run > 10) {
2711 /* no chunk header, abort */
2718 if (c->buffer_end > c->buffer_ptr) {
2719 len = recv(c->fd, c->buffer_ptr,
2720 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2722 if (ff_neterrno() != AVERROR(EAGAIN) &&
2723 ff_neterrno() != AVERROR(EINTR))
2724 /* error : close connection */
2726 } else if (len == 0)
2727 /* end of connection : close it */
2730 c->chunk_size -= len;
2731 c->buffer_ptr += len;
2732 c->data_count += len;
2733 update_datarate(&c->datarate, c->data_count);
2737 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2738 if (c->buffer[0] != 'f' ||
2739 c->buffer[1] != 'm') {
2740 http_log("Feed stream has become desynchronized -- disconnecting\n");
2745 if (c->buffer_ptr >= c->buffer_end) {
2746 FFStream *feed = c->stream;
2747 /* a packet has been received : write it in the store, except
2749 if (c->data_count > FFM_PACKET_SIZE) {
2750 /* XXX: use llseek or url_seek */
2751 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2752 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2753 http_log("Error writing to feed file: %s\n", strerror(errno));
2757 feed->feed_write_index += FFM_PACKET_SIZE;
2758 /* update file size */
2759 if (feed->feed_write_index > c->stream->feed_size)
2760 feed->feed_size = feed->feed_write_index;
2762 /* handle wrap around if max file size reached */
2763 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2764 feed->feed_write_index = FFM_PACKET_SIZE;
2767 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2768 http_log("Error writing index to feed file: %s\n", strerror(errno));
2772 /* wake up any waiting connections */
2773 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2774 if (c1->state == HTTPSTATE_WAIT_FEED &&
2775 c1->stream->feed == c->stream->feed)
2776 c1->state = HTTPSTATE_SEND_DATA;
2779 /* We have a header in our hands that contains useful data */
2780 AVFormatContext *s = avformat_alloc_context();
2782 AVInputFormat *fmt_in;
2788 /* use feed output format name to find corresponding input format */
2789 fmt_in = av_find_input_format(feed->fmt->name);
2793 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2794 0, NULL, NULL, NULL, NULL);
2798 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2803 /* Now we have the actual streams */
2804 if (s->nb_streams != feed->nb_streams) {
2805 avformat_close_input(&s);
2807 http_log("Feed '%s' stream number does not match registered feed\n",
2808 c->stream->feed_filename);
2812 for (i = 0; i < s->nb_streams; i++) {
2813 AVStream *fst = feed->streams[i];
2814 AVStream *st = s->streams[i];
2815 avcodec_copy_context(fst->codec, st->codec);
2818 avformat_close_input(&s);
2821 c->buffer_ptr = c->buffer;
2826 c->stream->feed_opened = 0;
2828 /* wake up any waiting connections to stop waiting for feed */
2829 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2830 if (c1->state == HTTPSTATE_WAIT_FEED &&
2831 c1->stream->feed == c->stream->feed)
2832 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2837 /********************************************************************/
2840 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2847 str = RTSP_STATUS_CODE2STRING(error_number);
2849 str = "Unknown Error";
2851 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2852 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2854 /* output GMT time */
2857 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2858 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2861 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2863 rtsp_reply_header(c, error_number);
2864 avio_printf(c->pb, "\r\n");
2867 static int rtsp_parse_request(HTTPContext *c)
2869 const char *p, *p1, *p2;
2875 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2877 c->buffer_ptr[0] = '\0';
2880 get_word(cmd, sizeof(cmd), &p);
2881 get_word(url, sizeof(url), &p);
2882 get_word(protocol, sizeof(protocol), &p);
2884 av_strlcpy(c->method, cmd, sizeof(c->method));
2885 av_strlcpy(c->url, url, sizeof(c->url));
2886 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2888 if (avio_open_dyn_buf(&c->pb) < 0) {
2889 /* XXX: cannot do more */
2890 c->pb = NULL; /* safety */
2894 /* check version name */
2895 if (strcmp(protocol, "RTSP/1.0") != 0) {
2896 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2900 /* parse each header line */
2901 /* skip to next line */
2902 while (*p != '\n' && *p != '\0')
2906 while (*p != '\0') {
2907 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2911 if (p2 > p && p2[-1] == '\r')
2913 /* skip empty line */
2917 if (len > sizeof(line) - 1)
2918 len = sizeof(line) - 1;
2919 memcpy(line, p, len);
2921 ff_rtsp_parse_line(header, line, NULL, NULL);
2925 /* handle sequence number */
2926 c->seq = header->seq;
2928 if (!strcmp(cmd, "DESCRIBE"))
2929 rtsp_cmd_describe(c, url);
2930 else if (!strcmp(cmd, "OPTIONS"))
2931 rtsp_cmd_options(c, url);
2932 else if (!strcmp(cmd, "SETUP"))
2933 rtsp_cmd_setup(c, url, header);
2934 else if (!strcmp(cmd, "PLAY"))
2935 rtsp_cmd_play(c, url, header);
2936 else if (!strcmp(cmd, "PAUSE"))
2937 rtsp_cmd_interrupt(c, url, header, 1);
2938 else if (!strcmp(cmd, "TEARDOWN"))
2939 rtsp_cmd_interrupt(c, url, header, 0);
2941 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2944 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2945 c->pb = NULL; /* safety */
2947 /* XXX: cannot do more */
2950 c->buffer_ptr = c->pb_buffer;
2951 c->buffer_end = c->pb_buffer + len;
2952 c->state = RTSPSTATE_SEND_REPLY;
2956 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2957 struct in_addr my_ip)
2959 AVFormatContext *avc;
2960 AVStream *avs = NULL;
2961 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2962 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2965 avc = avformat_alloc_context();
2966 if (avc == NULL || !rtp_format) {
2969 avc->oformat = rtp_format;
2970 av_dict_set(&avc->metadata, "title",
2971 entry ? entry->value : "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_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3297 rtp_c = find_rtp_session_with_url(url, h->session_id);
3299 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3304 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3305 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3306 rtsp_reply_error(c, RTSP_STATUS_STATE);
3309 rtp_c->state = HTTPSTATE_READY;
3310 rtp_c->first_pts = AV_NOPTS_VALUE;
3313 /* now everything is OK, so we can send the connection parameters */
3314 rtsp_reply_header(c, RTSP_STATUS_OK);
3316 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3317 avio_printf(c->pb, "\r\n");
3320 close_connection(rtp_c);
3323 /********************************************************************/
3326 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3327 FFStream *stream, const char *session_id,
3328 enum RTSPLowerTransport rtp_protocol)
3330 HTTPContext *c = NULL;
3331 const char *proto_str;
3333 /* XXX: should output a warning page when coming
3334 close to the connection limit */
3335 if (nb_connections >= nb_max_connections)
3338 /* add a new connection */
3339 c = av_mallocz(sizeof(HTTPContext));
3344 c->poll_entry = NULL;
3345 c->from_addr = *from_addr;
3346 c->buffer_size = IOBUFFER_INIT_SIZE;
3347 c->buffer = av_malloc(c->buffer_size);
3352 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3353 c->state = HTTPSTATE_READY;
3354 c->is_packetized = 1;
3355 c->rtp_protocol = rtp_protocol;
3357 /* protocol is shown in statistics */
3358 switch(c->rtp_protocol) {
3359 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3360 proto_str = "MCAST";
3362 case RTSP_LOWER_TRANSPORT_UDP:
3365 case RTSP_LOWER_TRANSPORT_TCP:
3372 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3373 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3375 current_bandwidth += stream->bandwidth;
3377 c->next = first_http_ctx;
3389 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3390 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3392 static int rtp_new_av_stream(HTTPContext *c,
3393 int stream_index, struct sockaddr_in *dest_addr,
3394 HTTPContext *rtsp_c)
3396 AVFormatContext *ctx;
3399 URLContext *h = NULL;
3401 int max_packet_size;
3403 /* now we can open the relevant output stream */
3404 ctx = avformat_alloc_context();
3407 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3409 st = av_mallocz(sizeof(AVStream));
3412 ctx->nb_streams = 1;
3413 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3416 ctx->streams[0] = st;
3418 if (!c->stream->feed ||
3419 c->stream->feed == c->stream)
3420 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3423 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3425 st->priv_data = NULL;
3427 /* build destination RTP address */
3428 ipaddr = inet_ntoa(dest_addr->sin_addr);
3430 switch(c->rtp_protocol) {
3431 case RTSP_LOWER_TRANSPORT_UDP:
3432 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3435 /* XXX: also pass as parameter to function ? */
3436 if (c->stream->is_multicast) {
3438 ttl = c->stream->multicast_ttl;
3441 snprintf(ctx->filename, sizeof(ctx->filename),
3442 "rtp://%s:%d?multicast=1&ttl=%d",
3443 ipaddr, ntohs(dest_addr->sin_port), ttl);
3445 snprintf(ctx->filename, sizeof(ctx->filename),
3446 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3449 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3451 c->rtp_handles[stream_index] = h;
3452 max_packet_size = h->max_packet_size;
3454 case RTSP_LOWER_TRANSPORT_TCP:
3457 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3463 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3464 ipaddr, ntohs(dest_addr->sin_port),
3465 c->stream->filename, stream_index, c->protocol);
3467 /* normally, no packets should be output here, but the packet size may
3469 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3470 /* XXX: close stream */
3473 if (avformat_write_header(ctx, NULL) < 0) {
3481 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3484 c->rtp_ctx[stream_index] = ctx;
3488 /********************************************************************/
3489 /* ffserver initialization */
3491 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3495 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3498 fst = av_mallocz(sizeof(AVStream));
3502 fst->codec = avcodec_alloc_context3(NULL);
3503 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3504 if (codec->extradata_size) {
3505 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3506 memcpy(fst->codec->extradata, codec->extradata,
3507 codec->extradata_size);
3510 /* live streams must use the actual feed's codec since it may be
3511 * updated later to carry extradata needed by them.
3515 fst->priv_data = av_mallocz(sizeof(FeedData));
3516 fst->index = stream->nb_streams;
3517 avpriv_set_pts_info(fst, 33, 1, 90000);
3518 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3519 stream->streams[stream->nb_streams++] = fst;
3523 /* return the stream number in the feed */
3524 static int add_av_stream(FFStream *feed, AVStream *st)
3527 AVCodecContext *av, *av1;
3531 for(i=0;i<feed->nb_streams;i++) {
3532 st = feed->streams[i];
3534 if (av1->codec_id == av->codec_id &&
3535 av1->codec_type == av->codec_type &&
3536 av1->bit_rate == av->bit_rate) {
3538 switch(av->codec_type) {
3539 case AVMEDIA_TYPE_AUDIO:
3540 if (av1->channels == av->channels &&
3541 av1->sample_rate == av->sample_rate)
3544 case AVMEDIA_TYPE_VIDEO:
3545 if (av1->width == av->width &&
3546 av1->height == av->height &&
3547 av1->time_base.den == av->time_base.den &&
3548 av1->time_base.num == av->time_base.num &&
3549 av1->gop_size == av->gop_size)
3558 fst = add_av_stream1(feed, av, 0);
3561 return feed->nb_streams - 1;
3564 static void remove_stream(FFStream *stream)
3568 while (*ps != NULL) {
3576 /* specific MPEG4 handling : we extract the raw parameters */
3577 static void extract_mpeg4_header(AVFormatContext *infile)
3579 int mpeg4_count, i, size;
3584 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3587 for(i=0;i<infile->nb_streams;i++) {
3588 st = infile->streams[i];
3589 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3590 st->codec->extradata_size == 0) {
3597 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3598 while (mpeg4_count > 0) {
3599 if (av_read_frame(infile, &pkt) < 0)
3601 st = infile->streams[pkt.stream_index];
3602 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3603 st->codec->extradata_size == 0) {
3604 av_freep(&st->codec->extradata);
3605 /* fill extradata with the header */
3606 /* XXX: we make hard suppositions here ! */
3608 while (p < pkt.data + pkt.size - 4) {
3609 /* stop when vop header is found */
3610 if (p[0] == 0x00 && p[1] == 0x00 &&
3611 p[2] == 0x01 && p[3] == 0xb6) {
3612 size = p - pkt.data;
3613 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3614 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3615 st->codec->extradata_size = size;
3616 memcpy(st->codec->extradata, pkt.data, size);
3623 av_free_packet(&pkt);
3627 /* compute the needed AVStream for each file */
3628 static void build_file_streams(void)
3630 FFStream *stream, *stream_next;
3633 /* gather all streams */
3634 for(stream = first_stream; stream != NULL; stream = stream_next) {
3635 AVFormatContext *infile = NULL;
3636 stream_next = stream->next;
3637 if (stream->stream_type == STREAM_TYPE_LIVE &&
3639 /* the stream comes from a file */
3640 /* try to open the file */
3642 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3643 /* specific case : if transport stream output to RTP,
3644 we use a raw transport stream reader */
3645 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3648 if (!stream->feed_filename[0]) {
3649 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3653 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3654 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3655 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3656 /* remove stream (no need to spend more time on it) */
3658 remove_stream(stream);
3660 /* find all the AVStreams inside and reference them in
3662 if (avformat_find_stream_info(infile, NULL) < 0) {
3663 http_log("Could not find codec parameters from '%s'\n",
3664 stream->feed_filename);
3665 avformat_close_input(&infile);
3668 extract_mpeg4_header(infile);
3670 for(i=0;i<infile->nb_streams;i++)
3671 add_av_stream1(stream, infile->streams[i]->codec, 1);
3673 avformat_close_input(&infile);
3679 /* compute the needed AVStream for each feed */
3680 static void build_feed_streams(void)
3682 FFStream *stream, *feed;
3685 /* gather all streams */
3686 for(stream = first_stream; stream != NULL; stream = stream->next) {
3687 feed = stream->feed;
3689 if (stream->is_feed) {
3690 for(i=0;i<stream->nb_streams;i++)
3691 stream->feed_streams[i] = i;
3693 /* we handle a stream coming from a feed */
3694 for(i=0;i<stream->nb_streams;i++)
3695 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3700 /* create feed files if needed */
3701 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3704 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3705 /* See if it matches */
3706 AVFormatContext *s = NULL;
3709 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3710 /* set buffer size */
3711 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3712 /* Now see if it matches */
3713 if (s->nb_streams == feed->nb_streams) {
3715 for(i=0;i<s->nb_streams;i++) {
3717 sf = feed->streams[i];
3720 if (sf->index != ss->index ||
3722 http_log("Index & Id do not match for stream %d (%s)\n",
3723 i, feed->feed_filename);
3726 AVCodecContext *ccf, *ccs;
3730 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3732 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3733 http_log("Codecs do not match for stream %d\n", i);
3735 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3736 http_log("Codec bitrates do not match for stream %d\n", i);
3738 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3739 if (CHECK_CODEC(time_base.den) ||
3740 CHECK_CODEC(time_base.num) ||
3741 CHECK_CODEC(width) ||
3742 CHECK_CODEC(height)) {
3743 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3746 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3747 if (CHECK_CODEC(sample_rate) ||
3748 CHECK_CODEC(channels) ||
3749 CHECK_CODEC(frame_size)) {
3750 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3754 http_log("Unknown codec type\n");
3762 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3763 feed->feed_filename, s->nb_streams, feed->nb_streams);
3765 avformat_close_input(&s);
3767 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3768 feed->feed_filename);
3771 if (feed->readonly) {
3772 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3773 feed->feed_filename);
3776 unlink(feed->feed_filename);
3779 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3780 AVFormatContext *s = avformat_alloc_context();
3782 if (feed->readonly) {
3783 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3784 feed->feed_filename);
3788 /* only write the header of the ffm file */
3789 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3790 http_log("Could not open output feed file '%s'\n",
3791 feed->feed_filename);
3794 s->oformat = feed->fmt;
3795 s->nb_streams = feed->nb_streams;
3796 s->streams = feed->streams;
3797 if (avformat_write_header(s, NULL) < 0) {
3798 http_log("Container doesn't support the required parameters\n");
3801 /* XXX: need better API */
3802 av_freep(&s->priv_data);
3806 avformat_free_context(s);
3808 /* get feed size and write index */
3809 fd = open(feed->feed_filename, O_RDONLY);
3811 http_log("Could not open output feed file '%s'\n",
3812 feed->feed_filename);
3816 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3817 feed->feed_size = lseek(fd, 0, SEEK_END);
3818 /* ensure that we do not wrap before the end of file */
3819 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3820 feed->feed_max_size = feed->feed_size;
3826 /* compute the bandwidth used by each stream */
3827 static void compute_bandwidth(void)
3833 for(stream = first_stream; stream != NULL; stream = stream->next) {
3835 for(i=0;i<stream->nb_streams;i++) {
3836 AVStream *st = stream->streams[i];
3837 switch(st->codec->codec_type) {
3838 case AVMEDIA_TYPE_AUDIO:
3839 case AVMEDIA_TYPE_VIDEO:
3840 bandwidth += st->codec->bit_rate;
3846 stream->bandwidth = (bandwidth + 999) / 1000;
3850 /* add a codec and set the default parameters */
3851 static void add_codec(FFStream *stream, AVCodecContext *av)
3855 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3858 /* compute default parameters */
3859 switch(av->codec_type) {
3860 case AVMEDIA_TYPE_AUDIO:
3861 if (av->bit_rate == 0)
3862 av->bit_rate = 64000;
3863 if (av->sample_rate == 0)
3864 av->sample_rate = 22050;
3865 if (av->channels == 0)
3868 case AVMEDIA_TYPE_VIDEO:
3869 if (av->bit_rate == 0)
3870 av->bit_rate = 64000;
3871 if (av->time_base.num == 0){
3872 av->time_base.den = 5;
3873 av->time_base.num = 1;
3875 if (av->width == 0 || av->height == 0) {
3879 /* Bitrate tolerance is less for streaming */
3880 if (av->bit_rate_tolerance == 0)
3881 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3882 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3887 if (av->max_qdiff == 0)
3889 av->qcompress = 0.5;
3892 if (!av->nsse_weight)
3893 av->nsse_weight = 8;
3895 av->frame_skip_cmp = FF_CMP_DCTMAX;
3897 av->me_method = ME_EPZS;
3898 av->rc_buffer_aggressivity = 1.0;
3901 av->rc_eq = av_strdup("tex^qComp");
3902 if (!av->i_quant_factor)
3903 av->i_quant_factor = -0.8;
3904 if (!av->b_quant_factor)
3905 av->b_quant_factor = 1.25;
3906 if (!av->b_quant_offset)
3907 av->b_quant_offset = 1.25;
3908 if (!av->rc_max_rate)
3909 av->rc_max_rate = av->bit_rate * 2;
3911 if (av->rc_max_rate && !av->rc_buffer_size) {
3912 av->rc_buffer_size = av->rc_max_rate;
3921 st = av_mallocz(sizeof(AVStream));
3924 st->codec = avcodec_alloc_context3(NULL);
3925 stream->streams[stream->nb_streams++] = st;
3926 memcpy(st->codec, av, sizeof(AVCodecContext));
3929 static enum AVCodecID opt_codec(const char *name, enum AVMediaType type)
3931 AVCodec *codec = avcodec_find_encoder_by_name(name);
3933 if (!codec || codec->type != type)
3934 return AV_CODEC_ID_NONE;
3938 static int ffserver_opt_default(const char *opt, const char *arg,
3939 AVCodecContext *avctx, int type)
3942 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3944 ret = av_opt_set(avctx, opt, arg, 0);
3948 static int ffserver_opt_preset(const char *arg,
3949 AVCodecContext *avctx, int type,
3950 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3953 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3955 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3957 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3958 codec ? codec->name : NULL))) {
3959 fprintf(stderr, "File for preset '%s' not found\n", arg);
3964 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3965 if(line[0] == '#' && !e)
3967 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3969 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3973 if(!strcmp(tmp, "acodec")){
3974 *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
3975 }else if(!strcmp(tmp, "vcodec")){
3976 *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
3977 }else if(!strcmp(tmp, "scodec")){
3978 /* opt_subtitle_codec(tmp2); */
3979 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3980 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3991 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename, const char *mime_type)
3993 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3996 AVOutputFormat *stream_fmt;
3997 char stream_format_name[64];
3999 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4000 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4009 static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...)
4013 av_log(NULL, log_level, "%s:%d: ", filename, line_num);
4014 av_vlog(NULL, log_level, fmt, vl);
4020 static int parse_ffconfig(const char *filename)
4025 char arg[1024], arg2[1024];
4027 int val, errors, warnings, line_num;
4028 FFStream **last_stream, *stream, *redirect;
4029 FFStream **last_feed, *feed, *s;
4030 AVCodecContext audio_enc, video_enc;
4031 enum AVCodecID audio_id, video_id;
4034 f = fopen(filename, "r");
4036 ret = AVERROR(errno);
4037 av_log(NULL, AV_LOG_ERROR, "Could not open the configuration file '%s'\n", filename);
4041 errors = warnings = 0;
4043 first_stream = NULL;
4044 last_stream = &first_stream;
4046 last_feed = &first_feed;
4050 audio_id = AV_CODEC_ID_NONE;
4051 video_id = AV_CODEC_ID_NONE;
4052 #define ERROR(...) report_config_error(filename, line_num, AV_LOG_ERROR, &errors, __VA_ARGS__)
4053 #define WARNING(...) report_config_error(filename, line_num, AV_LOG_WARNING, &warnings, __VA_ARGS__)
4056 if (fgets(line, sizeof(line), f) == NULL)
4060 while (av_isspace(*p))
4062 if (*p == '\0' || *p == '#')
4065 get_arg(cmd, sizeof(cmd), &p);
4067 if (!av_strcasecmp(cmd, "Port")) {
4068 get_arg(arg, sizeof(arg), &p);
4070 if (val < 1 || val > 65536) {
4071 ERROR("Invalid_port: %s\n", arg);
4073 my_http_addr.sin_port = htons(val);
4074 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4075 get_arg(arg, sizeof(arg), &p);
4076 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4077 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4079 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4080 WARNING("NoDaemon option has no effect, you should remove it\n");
4081 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4082 get_arg(arg, sizeof(arg), &p);
4084 if (val < 1 || val > 65536) {
4085 ERROR("%s:%d: Invalid port: %s\n", arg);
4087 my_rtsp_addr.sin_port = htons(atoi(arg));
4088 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4089 get_arg(arg, sizeof(arg), &p);
4090 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4091 ERROR("Invalid host/IP address: %s\n", arg);
4093 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4094 get_arg(arg, sizeof(arg), &p);
4096 if (val < 1 || val > 65536) {
4097 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4099 nb_max_http_connections = val;
4100 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4101 get_arg(arg, sizeof(arg), &p);
4103 if (val < 1 || val > nb_max_http_connections) {
4104 ERROR("Invalid MaxClients: %s\n", arg);
4106 nb_max_connections = val;
4108 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4110 get_arg(arg, sizeof(arg), &p);
4111 llval = strtoll(arg, NULL, 10);
4112 if (llval < 10 || llval > 10000000) {
4113 ERROR("Invalid MaxBandwidth: %s\n", arg);
4115 max_bandwidth = llval;
4116 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4117 if (!ffserver_debug)
4118 get_arg(logfilename, sizeof(logfilename), &p);
4119 } else if (!av_strcasecmp(cmd, "<Feed")) {
4120 /*********************************************/
4121 /* Feed related options */
4123 if (stream || feed) {
4124 ERROR("Already in a tag\n");
4126 feed = av_mallocz(sizeof(FFStream));
4128 ret = AVERROR(ENOMEM);
4131 get_arg(feed->filename, sizeof(feed->filename), &p);
4132 q = strrchr(feed->filename, '>');
4136 for (s = first_feed; s; s = s->next) {
4137 if (!strcmp(feed->filename, s->filename)) {
4138 ERROR("Feed '%s' already registered\n", s->filename);
4142 feed->fmt = av_guess_format("ffm", NULL, NULL);
4143 /* default feed file */
4144 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4145 "/tmp/%s.ffm", feed->filename);
4146 feed->feed_max_size = 5 * 1024 * 1024;
4148 feed->feed = feed; /* self feeding :-) */
4150 /* add in stream list */
4151 *last_stream = feed;
4152 last_stream = &feed->next;
4153 /* add in feed list */
4155 last_feed = &feed->next_feed;
4157 } else if (!av_strcasecmp(cmd, "Launch")) {
4161 feed->child_argv = av_mallocz(64 * sizeof(char *));
4162 if (!feed->child_argv) {
4163 ret = AVERROR(ENOMEM);
4166 for (i = 0; i < 62; i++) {
4167 get_arg(arg, sizeof(arg), &p);
4171 feed->child_argv[i] = av_strdup(arg);
4172 if (!feed->child_argv[i]) {
4173 ret = AVERROR(ENOMEM);
4178 feed->child_argv[i] =
4179 av_asprintf("http://%s:%d/%s",
4180 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4181 inet_ntoa(my_http_addr.sin_addr), ntohs(my_http_addr.sin_port),
4183 if (!feed->child_argv[i]) {
4184 ret = AVERROR(ENOMEM);
4188 } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
4190 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4191 feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile");
4192 } else if (stream) {
4193 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4195 } else if (!av_strcasecmp(cmd, "Truncate")) {
4197 get_arg(arg, sizeof(arg), &p);
4198 /* assume Truncate is true in case no argument is specified */
4202 WARNING("Truncate N syntax in configuration file is deprecated, "
4203 "use Truncate alone with no arguments\n");
4204 feed->truncate = strtod(arg, NULL);
4207 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4212 get_arg(arg, sizeof(arg), &p);
4214 fsize = strtod(p1, &p1);
4215 switch(av_toupper(*p1)) {
4220 fsize *= 1024 * 1024;
4223 fsize *= 1024 * 1024 * 1024;
4226 feed->feed_max_size = (int64_t)fsize;
4227 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4228 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4231 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4233 ERROR("No corresponding <Feed> for </Feed>\n");
4236 } else if (!av_strcasecmp(cmd, "<Stream")) {
4237 /*********************************************/
4238 /* Stream related options */
4240 if (stream || feed) {
4241 ERROR("Already in a tag\n");
4244 stream = av_mallocz(sizeof(FFStream));
4246 ret = AVERROR(ENOMEM);
4249 get_arg(stream->filename, sizeof(stream->filename), &p);
4250 q = strrchr(stream->filename, '>');
4254 for (s = first_stream; s; s = s->next) {
4255 if (!strcmp(stream->filename, s->filename)) {
4256 ERROR("Stream '%s' already registered\n", s->filename);
4260 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4261 avcodec_get_context_defaults3(&video_enc, NULL);
4262 avcodec_get_context_defaults3(&audio_enc, NULL);
4264 audio_id = AV_CODEC_ID_NONE;
4265 video_id = AV_CODEC_ID_NONE;
4267 audio_id = stream->fmt->audio_codec;
4268 video_id = stream->fmt->video_codec;
4271 *last_stream = stream;
4272 last_stream = &stream->next;
4274 } else if (!av_strcasecmp(cmd, "Feed")) {
4275 get_arg(arg, sizeof(arg), &p);
4280 while (sfeed != NULL) {
4281 if (!strcmp(sfeed->filename, arg))
4283 sfeed = sfeed->next_feed;
4286 ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg, stream->filename);
4288 stream->feed = sfeed;
4290 } else if (!av_strcasecmp(cmd, "Format")) {
4291 get_arg(arg, sizeof(arg), &p);
4293 if (!strcmp(arg, "status")) {
4294 stream->stream_type = STREAM_TYPE_STATUS;
4297 stream->stream_type = STREAM_TYPE_LIVE;
4298 /* JPEG cannot be used here, so use single frame MJPEG */
4299 if (!strcmp(arg, "jpeg"))
4300 strcpy(arg, "mjpeg");
4301 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4303 ERROR("Unknown Format: %s\n", arg);
4307 audio_id = stream->fmt->audio_codec;
4308 video_id = stream->fmt->video_codec;
4311 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4312 get_arg(arg, sizeof(arg), &p);
4314 stream->ifmt = av_find_input_format(arg);
4315 if (!stream->ifmt) {
4316 ERROR("Unknown input format: %s\n", arg);
4319 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4320 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4321 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4323 ERROR("FaviconURL only permitted for status streams\n");
4325 } else if (!av_strcasecmp(cmd, "Author") ||
4326 !av_strcasecmp(cmd, "Comment") ||
4327 !av_strcasecmp(cmd, "Copyright") ||
4328 !av_strcasecmp(cmd, "Title")) {
4329 get_arg(arg, sizeof(arg), &p);
4335 for (i = 0; i < strlen(cmd); i++)
4336 key[i] = av_tolower(cmd[i]);
4338 WARNING("'%s' option in configuration file is deprecated, "
4339 "use 'Metadata %s VALUE' instead\n", cmd, key);
4340 if ((ret = av_dict_set(&stream->metadata, key, arg, 0)) < 0) {
4341 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4342 key, arg, av_err2str(ret));
4345 } else if (!av_strcasecmp(cmd, "Metadata")) {
4346 get_arg(arg, sizeof(arg), &p);
4347 get_arg(arg2, sizeof(arg2), &p);
4350 if ((ret = av_dict_set(&stream->metadata, arg, arg2, 0)) < 0) {
4351 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4352 arg, arg2, av_err2str(ret));
4355 } else if (!av_strcasecmp(cmd, "Preroll")) {
4356 get_arg(arg, sizeof(arg), &p);
4358 stream->prebuffer = atof(arg) * 1000;
4359 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4361 stream->send_on_key = 1;
4362 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4363 get_arg(arg, sizeof(arg), &p);
4364 audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO);
4365 if (audio_id == AV_CODEC_ID_NONE) {
4366 ERROR("Unknown AudioCodec: %s\n", arg);
4368 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4369 get_arg(arg, sizeof(arg), &p);
4370 video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO);
4371 if (video_id == AV_CODEC_ID_NONE) {
4372 ERROR("Unknown VideoCodec: %s\n", arg);
4374 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4375 get_arg(arg, sizeof(arg), &p);
4377 stream->max_time = atof(arg) * 1000;
4378 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4379 get_arg(arg, sizeof(arg), &p);
4381 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4382 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4383 get_arg(arg, sizeof(arg), &p);
4385 audio_enc.channels = atoi(arg);
4386 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4387 get_arg(arg, sizeof(arg), &p);
4389 audio_enc.sample_rate = atoi(arg);
4390 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4392 int minrate, maxrate;
4394 get_arg(arg, sizeof(arg), &p);
4396 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4397 video_enc.rc_min_rate = minrate * 1000;
4398 video_enc.rc_max_rate = maxrate * 1000;
4400 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4403 } else if (!av_strcasecmp(cmd, "Debug")) {
4405 get_arg(arg, sizeof(arg), &p);
4406 video_enc.debug = strtol(arg,0,0);
4408 } else if (!av_strcasecmp(cmd, "Strict")) {
4410 get_arg(arg, sizeof(arg), &p);
4411 video_enc.strict_std_compliance = atoi(arg);
4413 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4415 get_arg(arg, sizeof(arg), &p);
4416 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4418 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4420 get_arg(arg, sizeof(arg), &p);
4421 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4423 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4424 get_arg(arg, sizeof(arg), &p);
4426 video_enc.bit_rate = atoi(arg) * 1000;
4428 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4429 get_arg(arg, sizeof(arg), &p);
4431 ret = av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4433 ERROR("Invalid video size '%s'\n", arg);
4435 if ((video_enc.width % 16) != 0 ||
4436 (video_enc.height % 16) != 0) {
4437 ERROR("Image size must be a multiple of 16\n");
4441 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4442 get_arg(arg, sizeof(arg), &p);
4444 AVRational frame_rate;
4445 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4446 ERROR("Incorrect frame rate: %s\n", arg);
4448 video_enc.time_base.num = frame_rate.den;
4449 video_enc.time_base.den = frame_rate.num;
4452 } else if (!av_strcasecmp(cmd, "PixelFormat")) {
4453 get_arg(arg, sizeof(arg), &p);
4455 video_enc.pix_fmt = av_get_pix_fmt(arg);
4456 if (video_enc.pix_fmt == AV_PIX_FMT_NONE) {
4457 ERROR("Unknown pixel format: %s\n", arg);
4460 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4461 get_arg(arg, sizeof(arg), &p);
4463 video_enc.gop_size = atoi(arg);
4464 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4466 video_enc.gop_size = 1;
4467 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4469 video_enc.mb_decision = FF_MB_DECISION_BITS;
4470 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4472 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4473 video_enc.flags |= CODEC_FLAG_4MV;
4475 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4476 !av_strcasecmp(cmd, "AVOptionAudio")) {
4477 AVCodecContext *avctx;
4479 get_arg(arg, sizeof(arg), &p);
4480 get_arg(arg2, sizeof(arg2), &p);
4481 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4483 type = AV_OPT_FLAG_VIDEO_PARAM;
4486 type = AV_OPT_FLAG_AUDIO_PARAM;
4488 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4489 ERROR("Error setting %s option to %s %s\n", cmd, arg, arg2);
4491 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4492 !av_strcasecmp(cmd, "AVPresetAudio")) {
4493 AVCodecContext *avctx;
4495 get_arg(arg, sizeof(arg), &p);
4496 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4498 video_enc.codec_id = video_id;
4499 type = AV_OPT_FLAG_VIDEO_PARAM;
4502 audio_enc.codec_id = audio_id;
4503 type = AV_OPT_FLAG_AUDIO_PARAM;
4505 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4506 ERROR("AVPreset error: %s\n", arg);
4508 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4509 get_arg(arg, sizeof(arg), &p);
4510 if ((strlen(arg) == 4) && stream)
4511 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4512 } else if (!av_strcasecmp(cmd, "BitExact")) {
4514 video_enc.flags |= CODEC_FLAG_BITEXACT;
4515 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4517 video_enc.dct_algo = FF_DCT_FASTINT;
4518 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4520 video_enc.idct_algo = FF_IDCT_SIMPLE;
4521 } else if (!av_strcasecmp(cmd, "Qscale")) {
4522 get_arg(arg, sizeof(arg), &p);
4524 video_enc.flags |= CODEC_FLAG_QSCALE;
4525 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4527 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4528 get_arg(arg, sizeof(arg), &p);
4530 video_enc.max_qdiff = atoi(arg);
4531 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4532 ERROR("VideoQDiff out of range\n");
4535 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4536 get_arg(arg, sizeof(arg), &p);
4538 video_enc.qmax = atoi(arg);
4539 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4540 ERROR("VideoQMax out of range\n");
4543 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4544 get_arg(arg, sizeof(arg), &p);
4546 video_enc.qmin = atoi(arg);
4547 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4548 ERROR("VideoQMin out of range\n");
4551 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4552 get_arg(arg, sizeof(arg), &p);
4554 video_enc.lumi_masking = atof(arg);
4555 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4556 get_arg(arg, sizeof(arg), &p);
4558 video_enc.dark_masking = atof(arg);
4559 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4560 video_id = AV_CODEC_ID_NONE;
4561 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4562 audio_id = AV_CODEC_ID_NONE;
4563 } else if (!av_strcasecmp(cmd, "ACL")) {
4564 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4565 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4567 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4569 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4570 get_arg(arg, sizeof(arg), &p);
4572 av_freep(&stream->rtsp_option);
4573 stream->rtsp_option = av_strdup(arg);
4575 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4576 get_arg(arg, sizeof(arg), &p);
4578 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4579 ERROR("Invalid host/IP address: %s\n", arg);
4581 stream->is_multicast = 1;
4582 stream->loop = 1; /* default is looping */
4584 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4585 get_arg(arg, sizeof(arg), &p);
4587 stream->multicast_port = atoi(arg);
4588 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4589 get_arg(arg, sizeof(arg), &p);
4591 stream->multicast_ttl = atoi(arg);
4592 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4595 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4597 ERROR("No corresponding <Stream> for </Stream>\n");
4599 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4600 if (audio_id != AV_CODEC_ID_NONE) {
4601 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4602 audio_enc.codec_id = audio_id;
4603 add_codec(stream, &audio_enc);
4605 if (video_id != AV_CODEC_ID_NONE) {
4606 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4607 video_enc.codec_id = video_id;
4608 add_codec(stream, &video_enc);
4613 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4614 /*********************************************/
4616 if (stream || feed || redirect) {
4617 ERROR("Already in a tag\n");
4619 redirect = av_mallocz(sizeof(FFStream));
4621 ret = AVERROR(ENOMEM);
4624 *last_stream = redirect;
4625 last_stream = &redirect->next;
4627 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4628 q = strrchr(redirect->filename, '>');
4631 redirect->stream_type = STREAM_TYPE_REDIRECT;
4633 } else if (!av_strcasecmp(cmd, "URL")) {
4635 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4636 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4638 ERROR("No corresponding <Redirect> for </Redirect>\n");
4640 if (!redirect->feed_filename[0]) {
4641 ERROR("No URL found for <Redirect>\n");
4645 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4646 ERROR("Loadable modules no longer supported\n");
4648 ERROR("Incorrect keyword: '%s'\n", cmd);
4658 return AVERROR(EINVAL);
4663 static void handle_child_exit(int sig)
4668 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4671 for (feed = first_feed; feed; feed = feed->next) {
4672 if (feed->pid == pid) {
4673 int uptime = time(0) - feed->pid_start;
4676 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4679 /* Turn off any more restarts */
4680 feed->child_argv = 0;
4685 need_to_start_children = 1;
4688 static void opt_debug(void)
4691 logfilename[0] = '-';
4694 void show_help_default(const char *opt, const char *arg)
4696 printf("usage: ffserver [options]\n"
4697 "Hyper fast multi format Audio/Video streaming server\n");
4699 show_help_options(options, "Main options:", 0, 0, 0);
4702 static const OptionDef options[] = {
4703 #include "cmdutils_common_opts.h"
4704 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4705 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4706 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4710 int main(int argc, char **argv)
4712 struct sigaction sigact = { { 0 } };
4715 config_filename = av_strdup("/etc/ffserver.conf");
4717 parse_loglevel(argc, argv, options);
4719 avformat_network_init();
4721 show_banner(argc, argv, options);
4723 my_program_name = argv[0];
4725 parse_options(NULL, argc, argv, options, NULL);
4727 unsetenv("http_proxy"); /* Kill the http_proxy */
4729 av_lfg_init(&random_state, av_get_random_seed());
4731 sigact.sa_handler = handle_child_exit;
4732 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4733 sigaction(SIGCHLD, &sigact, 0);
4735 if ((ret = parse_ffconfig(config_filename)) < 0) {
4736 fprintf(stderr, "Error reading configuration file '%s': %s\n",
4737 config_filename, av_err2str(ret));
4740 av_freep(&config_filename);
4742 /* open log file if needed */
4743 if (logfilename[0] != '\0') {
4744 if (!strcmp(logfilename, "-"))
4747 logfile = fopen(logfilename, "a");
4748 av_log_set_callback(http_av_log);
4751 build_file_streams();
4753 build_feed_streams();
4755 compute_bandwidth();
4758 signal(SIGPIPE, SIG_IGN);
4760 if (http_server() < 0) {
4761 http_log("Could not start server\n");