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);
576 if (ff_socket_nonblock(server_fd, 1) < 0)
577 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
582 /* start all multicast streams */
583 static void start_multicast(void)
588 struct sockaddr_in dest_addr = {0};
589 int default_port, stream_index;
592 for(stream = first_stream; stream != NULL; stream = stream->next) {
593 if (stream->is_multicast) {
594 unsigned random0 = av_lfg_get(&random_state);
595 unsigned random1 = av_lfg_get(&random_state);
596 /* open the RTP connection */
597 snprintf(session_id, sizeof(session_id), "%08x%08x",
600 /* choose a port if none given */
601 if (stream->multicast_port == 0) {
602 stream->multicast_port = default_port;
606 dest_addr.sin_family = AF_INET;
607 dest_addr.sin_addr = stream->multicast_ip;
608 dest_addr.sin_port = htons(stream->multicast_port);
610 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
611 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
615 if (open_input_stream(rtp_c, "") < 0) {
616 http_log("Could not open input stream for stream '%s'\n",
621 /* open each RTP stream */
622 for(stream_index = 0; stream_index < stream->nb_streams;
624 dest_addr.sin_port = htons(stream->multicast_port +
626 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
627 http_log("Could not open output stream '%s/streamid=%d'\n",
628 stream->filename, stream_index);
633 rtp_c->state = HTTPSTATE_SEND_DATA;
638 /* main loop of the HTTP server */
639 static int http_server(void)
641 int server_fd = 0, rtsp_server_fd = 0;
643 struct pollfd *poll_table, *poll_entry;
644 HTTPContext *c, *c_next;
646 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
647 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
651 if (my_http_addr.sin_port) {
652 server_fd = socket_open_listen(&my_http_addr);
659 if (my_rtsp_addr.sin_port) {
660 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
661 if (rtsp_server_fd < 0) {
663 closesocket(server_fd);
668 if (!rtsp_server_fd && !server_fd) {
669 http_log("HTTP and RTSP disabled.\n");
674 http_log("FFserver started.\n");
676 start_children(first_feed);
681 poll_entry = poll_table;
683 poll_entry->fd = server_fd;
684 poll_entry->events = POLLIN;
687 if (rtsp_server_fd) {
688 poll_entry->fd = rtsp_server_fd;
689 poll_entry->events = POLLIN;
693 /* wait for events on each HTTP handle */
700 case HTTPSTATE_SEND_HEADER:
701 case RTSPSTATE_SEND_REPLY:
702 case RTSPSTATE_SEND_PACKET:
703 c->poll_entry = poll_entry;
705 poll_entry->events = POLLOUT;
708 case HTTPSTATE_SEND_DATA_HEADER:
709 case HTTPSTATE_SEND_DATA:
710 case HTTPSTATE_SEND_DATA_TRAILER:
711 if (!c->is_packetized) {
712 /* for TCP, we output as much as we can
713 * (may need to put a limit) */
714 c->poll_entry = poll_entry;
716 poll_entry->events = POLLOUT;
719 /* when ffserver is doing the timing, we work by
720 looking at which packet needs to be sent every
722 /* one tick wait XXX: 10 ms assumed */
727 case HTTPSTATE_WAIT_REQUEST:
728 case HTTPSTATE_RECEIVE_DATA:
729 case HTTPSTATE_WAIT_FEED:
730 case RTSPSTATE_WAIT_REQUEST:
731 /* need to catch errors */
732 c->poll_entry = poll_entry;
734 poll_entry->events = POLLIN;/* Maybe this will work */
738 c->poll_entry = NULL;
744 /* wait for an event on one connection. We poll at least every
745 second to handle timeouts */
747 ret = poll(poll_table, poll_entry - poll_table, delay);
748 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
749 ff_neterrno() != AVERROR(EINTR))
753 cur_time = av_gettime() / 1000;
755 if (need_to_start_children) {
756 need_to_start_children = 0;
757 start_children(first_feed);
760 /* now handle the events */
761 for(c = first_http_ctx; c != NULL; c = c_next) {
763 if (handle_connection(c) < 0) {
765 /* close and free the connection */
770 poll_entry = poll_table;
772 /* new HTTP connection request ? */
773 if (poll_entry->revents & POLLIN)
774 new_connection(server_fd, 0);
777 if (rtsp_server_fd) {
778 /* new RTSP connection request ? */
779 if (poll_entry->revents & POLLIN)
780 new_connection(rtsp_server_fd, 1);
785 /* start waiting for a new HTTP/RTSP request */
786 static void start_wait_request(HTTPContext *c, int is_rtsp)
788 c->buffer_ptr = c->buffer;
789 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
792 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
793 c->state = RTSPSTATE_WAIT_REQUEST;
795 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
796 c->state = HTTPSTATE_WAIT_REQUEST;
800 static void http_send_too_busy_reply(int fd)
803 int len = snprintf(buffer, sizeof(buffer),
804 "HTTP/1.0 503 Server too busy\r\n"
805 "Content-type: text/html\r\n"
807 "<html><head><title>Too busy</title></head><body>\r\n"
808 "<p>The server is too busy to serve your request at this time.</p>\r\n"
809 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
810 "</body></html>\r\n",
811 nb_connections, nb_max_connections);
812 av_assert0(len < sizeof(buffer));
813 send(fd, buffer, len, 0);
817 static void new_connection(int server_fd, int is_rtsp)
819 struct sockaddr_in from_addr;
822 HTTPContext *c = NULL;
824 len = sizeof(from_addr);
825 fd = accept(server_fd, (struct sockaddr *)&from_addr,
828 http_log("error during accept %s\n", strerror(errno));
831 if (ff_socket_nonblock(fd, 1) < 0)
832 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
834 if (nb_connections >= nb_max_connections) {
835 http_send_too_busy_reply(fd);
839 /* add a new connection */
840 c = av_mallocz(sizeof(HTTPContext));
845 c->poll_entry = NULL;
846 c->from_addr = from_addr;
847 c->buffer_size = IOBUFFER_INIT_SIZE;
848 c->buffer = av_malloc(c->buffer_size);
852 c->next = first_http_ctx;
856 start_wait_request(c, is_rtsp);
868 static void close_connection(HTTPContext *c)
870 HTTPContext **cp, *c1;
872 AVFormatContext *ctx;
876 /* remove connection from list */
877 cp = &first_http_ctx;
878 while ((*cp) != NULL) {
886 /* remove references, if any (XXX: do it faster) */
887 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
892 /* remove connection associated resources */
896 /* close each frame parser */
897 for(i=0;i<c->fmt_in->nb_streams;i++) {
898 st = c->fmt_in->streams[i];
899 if (st->codec->codec)
900 avcodec_close(st->codec);
902 avformat_close_input(&c->fmt_in);
905 /* free RTP output streams if any */
908 nb_streams = c->stream->nb_streams;
910 for(i=0;i<nb_streams;i++) {
913 av_write_trailer(ctx);
914 av_dict_free(&ctx->metadata);
915 av_free(ctx->streams[0]);
918 h = c->rtp_handles[i];
925 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
928 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
929 av_write_trailer(ctx);
930 av_freep(&c->pb_buffer);
931 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
936 for(i=0; i<ctx->nb_streams; i++)
937 av_free(ctx->streams[i]);
938 av_freep(&ctx->streams);
939 av_freep(&ctx->priv_data);
941 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
942 current_bandwidth -= c->stream->bandwidth;
944 /* signal that there is no feed if we are the feeder socket */
945 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
946 c->stream->feed_opened = 0;
950 av_freep(&c->pb_buffer);
951 av_freep(&c->packet_buffer);
957 static int handle_connection(HTTPContext *c)
962 case HTTPSTATE_WAIT_REQUEST:
963 case RTSPSTATE_WAIT_REQUEST:
965 if ((c->timeout - cur_time) < 0)
967 if (c->poll_entry->revents & (POLLERR | POLLHUP))
970 /* no need to read if no events */
971 if (!(c->poll_entry->revents & POLLIN))
975 len = recv(c->fd, c->buffer_ptr, 1, 0);
977 if (ff_neterrno() != AVERROR(EAGAIN) &&
978 ff_neterrno() != AVERROR(EINTR))
980 } else if (len == 0) {
983 /* search for end of request. */
985 c->buffer_ptr += len;
987 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
988 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
989 /* request found : parse it and reply */
990 if (c->state == HTTPSTATE_WAIT_REQUEST) {
991 ret = http_parse_request(c);
993 ret = rtsp_parse_request(c);
997 } else if (ptr >= c->buffer_end) {
998 /* request too long: cannot do anything */
1000 } else goto read_loop;
1004 case HTTPSTATE_SEND_HEADER:
1005 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1008 /* no need to write if no events */
1009 if (!(c->poll_entry->revents & POLLOUT))
1011 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1013 if (ff_neterrno() != AVERROR(EAGAIN) &&
1014 ff_neterrno() != AVERROR(EINTR)) {
1015 goto close_connection;
1018 c->buffer_ptr += len;
1020 c->stream->bytes_served += len;
1021 c->data_count += len;
1022 if (c->buffer_ptr >= c->buffer_end) {
1023 av_freep(&c->pb_buffer);
1024 /* if error, exit */
1027 /* all the buffer was sent : synchronize to the incoming
1029 c->state = HTTPSTATE_SEND_DATA_HEADER;
1030 c->buffer_ptr = c->buffer_end = c->buffer;
1035 case HTTPSTATE_SEND_DATA:
1036 case HTTPSTATE_SEND_DATA_HEADER:
1037 case HTTPSTATE_SEND_DATA_TRAILER:
1038 /* for packetized output, we consider we can always write (the
1039 input streams set the speed). It may be better to verify
1040 that we do not rely too much on the kernel queues */
1041 if (!c->is_packetized) {
1042 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1045 /* no need to read if no events */
1046 if (!(c->poll_entry->revents & POLLOUT))
1049 if (http_send_data(c) < 0)
1051 /* close connection if trailer sent */
1052 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1055 case HTTPSTATE_RECEIVE_DATA:
1056 /* no need to read if no events */
1057 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1059 if (!(c->poll_entry->revents & POLLIN))
1061 if (http_receive_data(c) < 0)
1064 case HTTPSTATE_WAIT_FEED:
1065 /* no need to read if no events */
1066 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1069 /* nothing to do, we'll be waken up by incoming feed packets */
1072 case RTSPSTATE_SEND_REPLY:
1073 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1074 goto close_connection;
1075 /* no need to write if no events */
1076 if (!(c->poll_entry->revents & POLLOUT))
1078 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1080 if (ff_neterrno() != AVERROR(EAGAIN) &&
1081 ff_neterrno() != AVERROR(EINTR)) {
1082 goto close_connection;
1085 c->buffer_ptr += len;
1086 c->data_count += len;
1087 if (c->buffer_ptr >= c->buffer_end) {
1088 /* all the buffer was sent : wait for a new request */
1089 av_freep(&c->pb_buffer);
1090 start_wait_request(c, 1);
1094 case RTSPSTATE_SEND_PACKET:
1095 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1096 av_freep(&c->packet_buffer);
1099 /* no need to write if no events */
1100 if (!(c->poll_entry->revents & POLLOUT))
1102 len = send(c->fd, c->packet_buffer_ptr,
1103 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1105 if (ff_neterrno() != AVERROR(EAGAIN) &&
1106 ff_neterrno() != AVERROR(EINTR)) {
1107 /* error : close connection */
1108 av_freep(&c->packet_buffer);
1112 c->packet_buffer_ptr += len;
1113 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1114 /* all the buffer was sent : wait for a new request */
1115 av_freep(&c->packet_buffer);
1116 c->state = RTSPSTATE_WAIT_REQUEST;
1120 case HTTPSTATE_READY:
1129 av_freep(&c->pb_buffer);
1133 static int extract_rates(char *rates, int ratelen, const char *request)
1137 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1138 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1139 const char *q = p + 7;
1141 while (*q && *q != '\n' && av_isspace(*q))
1144 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1150 memset(rates, 0xff, ratelen);
1153 while (*q && *q != '\n' && *q != ':')
1156 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1160 if (stream_no < ratelen && stream_no >= 0)
1161 rates[stream_no] = rate_no;
1163 while (*q && *q != '\n' && !av_isspace(*q))
1170 p = strchr(p, '\n');
1180 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1183 int best_bitrate = 100000000;
1186 for (i = 0; i < feed->nb_streams; i++) {
1187 AVCodecContext *feed_codec = feed->streams[i]->codec;
1189 if (feed_codec->codec_id != codec->codec_id ||
1190 feed_codec->sample_rate != codec->sample_rate ||
1191 feed_codec->width != codec->width ||
1192 feed_codec->height != codec->height)
1195 /* Potential stream */
1197 /* We want the fastest stream less than bit_rate, or the slowest
1198 * faster than bit_rate
1201 if (feed_codec->bit_rate <= bit_rate) {
1202 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1203 best_bitrate = feed_codec->bit_rate;
1207 if (feed_codec->bit_rate < best_bitrate) {
1208 best_bitrate = feed_codec->bit_rate;
1217 static int modify_current_stream(HTTPContext *c, char *rates)
1220 FFStream *req = c->stream;
1221 int action_required = 0;
1223 /* Not much we can do for a feed */
1227 for (i = 0; i < req->nb_streams; i++) {
1228 AVCodecContext *codec = req->streams[i]->codec;
1232 c->switch_feed_streams[i] = req->feed_streams[i];
1235 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1238 /* Wants off or slow */
1239 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1241 /* This doesn't work well when it turns off the only stream! */
1242 c->switch_feed_streams[i] = -2;
1243 c->feed_streams[i] = -2;
1248 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1249 action_required = 1;
1252 return action_required;
1255 /* XXX: factorize in utils.c ? */
1256 /* XXX: take care with different space meaning */
1257 static void skip_spaces(const char **pp)
1261 while (*p == ' ' || *p == '\t')
1266 static void get_word(char *buf, int buf_size, const char **pp)
1274 while (!av_isspace(*p) && *p != '\0') {
1275 if ((q - buf) < buf_size - 1)
1284 static void get_arg(char *buf, int buf_size, const char **pp)
1291 while (av_isspace(*p)) p++;
1294 if (*p == '\"' || *p == '\'')
1306 if ((q - buf) < buf_size - 1)
1311 if (quote && *p == quote)
1316 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1317 const char *p, const char *filename, int line_num)
1323 get_arg(arg, sizeof(arg), &p);
1324 if (av_strcasecmp(arg, "allow") == 0)
1325 acl.action = IP_ALLOW;
1326 else if (av_strcasecmp(arg, "deny") == 0)
1327 acl.action = IP_DENY;
1329 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1330 filename, line_num, arg);
1334 get_arg(arg, sizeof(arg), &p);
1336 if (resolve_host(&acl.first, arg) != 0) {
1337 fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1338 filename, line_num, arg);
1341 acl.last = acl.first;
1343 get_arg(arg, sizeof(arg), &p);
1346 if (resolve_host(&acl.last, arg) != 0) {
1347 fprintf(stderr, "%s:%d: ACL refers to invalid host or IP address '%s'\n",
1348 filename, line_num, arg);
1354 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1355 IPAddressACL **naclp = 0;
1361 naclp = &stream->acl;
1367 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1368 filename, line_num);
1374 naclp = &(*naclp)->next;
1383 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1388 IPAddressACL *acl = NULL;
1392 f = fopen(stream->dynamic_acl, "r");
1394 perror(stream->dynamic_acl);
1398 acl = av_mallocz(sizeof(IPAddressACL));
1402 if (fgets(line, sizeof(line), f) == NULL)
1406 while (av_isspace(*p))
1408 if (*p == '\0' || *p == '#')
1410 get_arg(cmd, sizeof(cmd), &p);
1412 if (!av_strcasecmp(cmd, "ACL"))
1413 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1420 static void free_acl_list(IPAddressACL *in_acl)
1422 IPAddressACL *pacl,*pacl2;
1432 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1434 enum IPAddressAction last_action = IP_DENY;
1436 struct in_addr *src = &c->from_addr.sin_addr;
1437 unsigned long src_addr = src->s_addr;
1439 for (acl = in_acl; acl; acl = acl->next) {
1440 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1441 return (acl->action == IP_ALLOW) ? 1 : 0;
1442 last_action = acl->action;
1445 /* Nothing matched, so return not the last action */
1446 return (last_action == IP_DENY) ? 1 : 0;
1449 static int validate_acl(FFStream *stream, HTTPContext *c)
1455 /* if stream->acl is null validate_acl_list will return 1 */
1456 ret = validate_acl_list(stream->acl, c);
1458 if (stream->dynamic_acl[0]) {
1459 acl = parse_dynamic_acl(stream, c);
1461 ret = validate_acl_list(acl, c);
1469 /* compute the real filename of a file by matching it without its
1470 extensions to all the stream's filenames */
1471 static void compute_real_filename(char *filename, int max_size)
1478 /* compute filename by matching without the file extensions */
1479 av_strlcpy(file1, filename, sizeof(file1));
1480 p = strrchr(file1, '.');
1483 for(stream = first_stream; stream != NULL; stream = stream->next) {
1484 av_strlcpy(file2, stream->filename, sizeof(file2));
1485 p = strrchr(file2, '.');
1488 if (!strcmp(file1, file2)) {
1489 av_strlcpy(filename, stream->filename, max_size);
1504 /* parse HTTP request and prepare header */
1505 static int http_parse_request(HTTPContext *c)
1509 enum RedirType redir_type;
1511 char info[1024], filename[1024];
1515 const char *mime_type;
1519 const char *useragent = 0;
1522 get_word(cmd, sizeof(cmd), &p);
1523 av_strlcpy(c->method, cmd, sizeof(c->method));
1525 if (!strcmp(cmd, "GET"))
1527 else if (!strcmp(cmd, "POST"))
1532 get_word(url, sizeof(url), &p);
1533 av_strlcpy(c->url, url, sizeof(c->url));
1535 get_word(protocol, sizeof(protocol), (const char **)&p);
1536 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1539 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1542 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1544 /* find the filename and the optional info string in the request */
1545 p1 = strchr(url, '?');
1547 av_strlcpy(info, p1, sizeof(info));
1552 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1554 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1555 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1557 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1561 p = strchr(p, '\n');
1568 redir_type = REDIR_NONE;
1569 if (av_match_ext(filename, "asx")) {
1570 redir_type = REDIR_ASX;
1571 filename[strlen(filename)-1] = 'f';
1572 } else if (av_match_ext(filename, "asf") &&
1573 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1574 /* if this isn't WMP or lookalike, return the redirector file */
1575 redir_type = REDIR_ASF;
1576 } else if (av_match_ext(filename, "rpm,ram")) {
1577 redir_type = REDIR_RAM;
1578 strcpy(filename + strlen(filename)-2, "m");
1579 } else if (av_match_ext(filename, "rtsp")) {
1580 redir_type = REDIR_RTSP;
1581 compute_real_filename(filename, sizeof(filename) - 1);
1582 } else if (av_match_ext(filename, "sdp")) {
1583 redir_type = REDIR_SDP;
1584 compute_real_filename(filename, sizeof(filename) - 1);
1587 // "redirect" / request to index.html
1588 if (!strlen(filename))
1589 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1591 stream = first_stream;
1592 while (stream != NULL) {
1593 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1595 stream = stream->next;
1597 if (stream == NULL) {
1598 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1599 http_log("File '%s' not found\n", url);
1604 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1605 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1607 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1608 c->http_error = 301;
1610 snprintf(q, c->buffer_size,
1611 "HTTP/1.0 301 Moved\r\n"
1613 "Content-type: text/html\r\n"
1615 "<html><head><title>Moved</title></head><body>\r\n"
1616 "You should be <a href=\"%s\">redirected</a>.\r\n"
1617 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1619 /* prepare output buffer */
1620 c->buffer_ptr = c->buffer;
1622 c->state = HTTPSTATE_SEND_HEADER;
1626 /* If this is WMP, get the rate information */
1627 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1628 if (modify_current_stream(c, ratebuf)) {
1629 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1630 if (c->switch_feed_streams[i] >= 0)
1631 c->switch_feed_streams[i] = -1;
1636 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1637 current_bandwidth += stream->bandwidth;
1639 /* If already streaming this feed, do not let start another feeder. */
1640 if (stream->feed_opened) {
1641 snprintf(msg, sizeof(msg), "This feed is already being received.");
1642 http_log("Feed '%s' already being received\n", stream->feed_filename);
1646 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1647 c->http_error = 503;
1649 snprintf(q, c->buffer_size,
1650 "HTTP/1.0 503 Server too busy\r\n"
1651 "Content-type: text/html\r\n"
1653 "<html><head><title>Too busy</title></head><body>\r\n"
1654 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1655 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1656 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1657 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1659 /* prepare output buffer */
1660 c->buffer_ptr = c->buffer;
1662 c->state = HTTPSTATE_SEND_HEADER;
1666 if (redir_type != REDIR_NONE) {
1667 const char *hostinfo = 0;
1669 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1670 if (av_strncasecmp(p, "Host:", 5) == 0) {
1674 p = strchr(p, '\n');
1685 while (av_isspace(*hostinfo))
1688 eoh = strchr(hostinfo, '\n');
1690 if (eoh[-1] == '\r')
1693 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1694 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1695 hostbuf[eoh - hostinfo] = 0;
1697 c->http_error = 200;
1699 switch(redir_type) {
1701 snprintf(q, c->buffer_size,
1702 "HTTP/1.0 200 ASX Follows\r\n"
1703 "Content-type: video/x-ms-asf\r\n"
1705 "<ASX Version=\"3\">\r\n"
1706 //"<!-- Autogenerated by ffserver -->\r\n"
1707 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1708 "</ASX>\r\n", hostbuf, filename, info);
1712 snprintf(q, c->buffer_size,
1713 "HTTP/1.0 200 RAM Follows\r\n"
1714 "Content-type: audio/x-pn-realaudio\r\n"
1716 "# Autogenerated by ffserver\r\n"
1717 "http://%s/%s%s\r\n", hostbuf, filename, info);
1721 snprintf(q, c->buffer_size,
1722 "HTTP/1.0 200 ASF Redirect follows\r\n"
1723 "Content-type: video/x-ms-asf\r\n"
1726 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1731 char hostname[256], *p;
1732 /* extract only hostname */
1733 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1734 p = strrchr(hostname, ':');
1737 snprintf(q, c->buffer_size,
1738 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1739 /* XXX: incorrect MIME type ? */
1740 "Content-type: application/x-rtsp\r\n"
1742 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1751 struct sockaddr_in my_addr;
1753 snprintf(q, c->buffer_size,
1754 "HTTP/1.0 200 OK\r\n"
1755 "Content-type: application/sdp\r\n"
1759 len = sizeof(my_addr);
1760 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1762 /* XXX: should use a dynamic buffer */
1763 sdp_data_size = prepare_sdp_description(stream,
1766 if (sdp_data_size > 0) {
1767 memcpy(q, sdp_data, sdp_data_size);
1779 /* prepare output buffer */
1780 c->buffer_ptr = c->buffer;
1782 c->state = HTTPSTATE_SEND_HEADER;
1788 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1792 stream->conns_served++;
1794 /* XXX: add there authenticate and IP match */
1797 /* if post, it means a feed is being sent */
1798 if (!stream->is_feed) {
1799 /* However it might be a status report from WMP! Let us log the
1800 * data as it might come handy one day. */
1801 const char *logline = 0;
1804 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1805 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1809 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1810 client_id = strtol(p + 18, 0, 10);
1811 p = strchr(p, '\n');
1819 char *eol = strchr(logline, '\n');
1824 if (eol[-1] == '\r')
1826 http_log("%.*s\n", (int) (eol - logline), logline);
1827 c->suppress_log = 1;
1832 http_log("\nGot request:\n%s\n", c->buffer);
1835 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1838 /* Now we have to find the client_id */
1839 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1840 if (wmpc->wmp_client_id == client_id)
1844 if (wmpc && modify_current_stream(wmpc, ratebuf))
1845 wmpc->switch_pending = 1;
1848 snprintf(msg, sizeof(msg), "POST command not handled");
1852 if (http_start_receive_data(c) < 0) {
1853 snprintf(msg, sizeof(msg), "could not open feed");
1857 c->state = HTTPSTATE_RECEIVE_DATA;
1862 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1863 http_log("\nGot request:\n%s\n", c->buffer);
1866 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1869 /* open input stream */
1870 if (open_input_stream(c, info) < 0) {
1871 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1875 /* prepare HTTP header */
1877 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1878 mime_type = c->stream->fmt->mime_type;
1880 mime_type = "application/x-octet-stream";
1881 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1883 /* for asf, we need extra headers */
1884 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1885 /* Need to allocate a client id */
1887 c->wmp_client_id = av_lfg_get(&random_state);
1889 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);
1891 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1892 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1893 q = c->buffer + strlen(c->buffer);
1895 /* prepare output buffer */
1897 c->buffer_ptr = c->buffer;
1899 c->state = HTTPSTATE_SEND_HEADER;
1902 c->http_error = 404;
1905 snprintf(q, c->buffer_size,
1906 "HTTP/1.0 404 Not Found\r\n"
1907 "Content-type: text/html\r\n"
1910 "<head><title>404 Not Found</title></head>\n"
1914 /* prepare output buffer */
1915 c->buffer_ptr = c->buffer;
1917 c->state = HTTPSTATE_SEND_HEADER;
1921 c->http_error = 200; /* horrible : we use this value to avoid
1922 going to the send data state */
1923 c->state = HTTPSTATE_SEND_HEADER;
1927 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1929 static const char suffix[] = " kMGTP";
1932 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1934 avio_printf(pb, "%"PRId64"%c", count, *s);
1937 static void compute_status(HTTPContext *c)
1946 if (avio_open_dyn_buf(&pb) < 0) {
1947 /* XXX: return an error ? */
1948 c->buffer_ptr = c->buffer;
1949 c->buffer_end = c->buffer;
1953 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1954 avio_printf(pb, "Content-type: text/html\r\n");
1955 avio_printf(pb, "Pragma: no-cache\r\n");
1956 avio_printf(pb, "\r\n");
1958 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1959 if (c->stream->feed_filename[0])
1960 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1961 avio_printf(pb, "</head>\n<body>");
1962 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1964 avio_printf(pb, "<h2>Available Streams</h2>\n");
1965 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1966 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");
1967 stream = first_stream;
1968 while (stream != NULL) {
1969 char sfilename[1024];
1972 if (stream->feed != stream) {
1973 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1974 eosf = sfilename + strlen(sfilename);
1975 if (eosf - sfilename >= 4) {
1976 if (strcmp(eosf - 4, ".asf") == 0)
1977 strcpy(eosf - 4, ".asx");
1978 else if (strcmp(eosf - 3, ".rm") == 0)
1979 strcpy(eosf - 3, ".ram");
1980 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1981 /* generate a sample RTSP director if
1982 unicast. Generate an SDP redirector if
1984 eosf = strrchr(sfilename, '.');
1986 eosf = sfilename + strlen(sfilename);
1987 if (stream->is_multicast)
1988 strcpy(eosf, ".sdp");
1990 strcpy(eosf, ".rtsp");
1994 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1995 sfilename, stream->filename);
1996 avio_printf(pb, "<td align=right> %d <td align=right> ",
1997 stream->conns_served);
1998 fmt_bytecount(pb, stream->bytes_served);
1999 switch(stream->stream_type) {
2000 case STREAM_TYPE_LIVE: {
2001 int audio_bit_rate = 0;
2002 int video_bit_rate = 0;
2003 const char *audio_codec_name = "";
2004 const char *video_codec_name = "";
2005 const char *audio_codec_name_extra = "";
2006 const char *video_codec_name_extra = "";
2008 for(i=0;i<stream->nb_streams;i++) {
2009 AVStream *st = stream->streams[i];
2010 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2011 switch(st->codec->codec_type) {
2012 case AVMEDIA_TYPE_AUDIO:
2013 audio_bit_rate += st->codec->bit_rate;
2015 if (*audio_codec_name)
2016 audio_codec_name_extra = "...";
2017 audio_codec_name = codec->name;
2020 case AVMEDIA_TYPE_VIDEO:
2021 video_bit_rate += st->codec->bit_rate;
2023 if (*video_codec_name)
2024 video_codec_name_extra = "...";
2025 video_codec_name = codec->name;
2028 case AVMEDIA_TYPE_DATA:
2029 video_bit_rate += st->codec->bit_rate;
2035 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",
2038 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2039 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2041 avio_printf(pb, "<td>%s", stream->feed->filename);
2043 avio_printf(pb, "<td>%s", stream->feed_filename);
2044 avio_printf(pb, "\n");
2048 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2052 stream = stream->next;
2054 avio_printf(pb, "</table>\n");
2056 stream = first_stream;
2057 while (stream != NULL) {
2058 if (stream->feed == stream) {
2059 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2061 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2068 /* This is somewhat linux specific I guess */
2069 snprintf(ps_cmd, sizeof(ps_cmd),
2070 "ps -o \"%%cpu,cputime\" --no-headers %d",
2073 pid_stat = popen(ps_cmd, "r");
2078 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2080 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2088 avio_printf(pb, "<p>");
2090 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");
2092 for (i = 0; i < stream->nb_streams; i++) {
2093 AVStream *st = stream->streams[i];
2094 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2095 const char *type = "unknown";
2096 char parameters[64];
2100 switch(st->codec->codec_type) {
2101 case AVMEDIA_TYPE_AUDIO:
2103 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2105 case AVMEDIA_TYPE_VIDEO:
2107 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2108 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2113 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2114 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2116 avio_printf(pb, "</table>\n");
2119 stream = stream->next;
2122 /* connection status */
2123 avio_printf(pb, "<h2>Connection Status</h2>\n");
2125 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2126 nb_connections, nb_max_connections);
2128 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2129 current_bandwidth, max_bandwidth);
2131 avio_printf(pb, "<table>\n");
2132 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");
2133 c1 = first_http_ctx;
2135 while (c1 != NULL) {
2141 for (j = 0; j < c1->stream->nb_streams; j++) {
2142 if (!c1->stream->feed)
2143 bitrate += c1->stream->streams[j]->codec->bit_rate;
2144 else if (c1->feed_streams[j] >= 0)
2145 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2150 p = inet_ntoa(c1->from_addr.sin_addr);
2151 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2153 c1->stream ? c1->stream->filename : "",
2154 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2157 http_state[c1->state]);
2158 fmt_bytecount(pb, bitrate);
2159 avio_printf(pb, "<td align=right>");
2160 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2161 avio_printf(pb, "<td align=right>");
2162 fmt_bytecount(pb, c1->data_count);
2163 avio_printf(pb, "\n");
2166 avio_printf(pb, "</table>\n");
2171 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2172 avio_printf(pb, "</body>\n</html>\n");
2174 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2175 c->buffer_ptr = c->pb_buffer;
2176 c->buffer_end = c->pb_buffer + len;
2179 static int open_input_stream(HTTPContext *c, const char *info)
2182 char input_filename[1024];
2183 AVFormatContext *s = NULL;
2184 int buf_size, i, ret;
2187 /* find file name */
2188 if (c->stream->feed) {
2189 strcpy(input_filename, c->stream->feed->feed_filename);
2190 buf_size = FFM_PACKET_SIZE;
2191 /* compute position (absolute time) */
2192 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2193 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2194 http_log("Invalid date specification '%s' for stream\n", buf);
2197 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2198 int prebuffer = strtol(buf, 0, 10);
2199 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2201 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2203 strcpy(input_filename, c->stream->feed_filename);
2205 /* compute position (relative time) */
2206 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2207 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2208 http_log("Invalid date specification '%s' for stream\n", buf);
2214 if (!input_filename[0]) {
2215 http_log("No filename was specified for stream\n");
2216 return AVERROR(EINVAL);
2220 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2221 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2225 /* set buffer size */
2226 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2228 s->flags |= AVFMT_FLAG_GENPTS;
2230 if (strcmp(s->iformat->name, "ffm") &&
2231 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2232 http_log("Could not find stream info for input '%s'\n", input_filename);
2233 avformat_close_input(&s);
2237 /* choose stream as clock source (we favor the video stream if
2238 * present) for packet sending */
2239 c->pts_stream_index = 0;
2240 for(i=0;i<c->stream->nb_streams;i++) {
2241 if (c->pts_stream_index == 0 &&
2242 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2243 c->pts_stream_index = i;
2247 if (c->fmt_in->iformat->read_seek)
2248 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2249 /* set the start time (needed for maxtime and RTP packet timing) */
2250 c->start_time = cur_time;
2251 c->first_pts = AV_NOPTS_VALUE;
2255 /* return the server clock (in us) */
2256 static int64_t get_server_clock(HTTPContext *c)
2258 /* compute current pts value from system time */
2259 return (cur_time - c->start_time) * 1000;
2262 /* return the estimated time at which the current packet must be sent
2264 static int64_t get_packet_send_clock(HTTPContext *c)
2266 int bytes_left, bytes_sent, frame_bytes;
2268 frame_bytes = c->cur_frame_bytes;
2269 if (frame_bytes <= 0)
2272 bytes_left = c->buffer_end - c->buffer_ptr;
2273 bytes_sent = frame_bytes - bytes_left;
2274 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2279 static int http_prepare_data(HTTPContext *c)
2282 AVFormatContext *ctx;
2284 av_freep(&c->pb_buffer);
2286 case HTTPSTATE_SEND_DATA_HEADER:
2287 ctx = avformat_alloc_context();
2290 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2291 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2293 for(i=0;i<c->stream->nb_streams;i++) {
2295 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2296 /* if file or feed, then just take streams from FFStream struct */
2297 if (!c->stream->feed ||
2298 c->stream->feed == c->stream)
2299 src = c->stream->streams[i];
2301 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2303 *(c->fmt_ctx.streams[i]) = *src;
2304 c->fmt_ctx.streams[i]->priv_data = 0;
2305 /* XXX: should be done in AVStream, not in codec */
2306 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2308 /* set output format parameters */
2309 c->fmt_ctx.oformat = c->stream->fmt;
2310 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2312 c->got_key_frame = 0;
2314 /* prepare header and save header data in a stream */
2315 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2316 /* XXX: potential leak */
2319 c->fmt_ctx.pb->seekable = 0;
2322 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2323 * Default value from FFmpeg
2324 * Try to set it using configuration option
2326 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2328 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2329 http_log("Error writing output header for stream '%s': %s\n",
2330 c->stream->filename, av_err2str(ret));
2333 av_dict_free(&c->fmt_ctx.metadata);
2335 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2336 c->buffer_ptr = c->pb_buffer;
2337 c->buffer_end = c->pb_buffer + len;
2339 c->state = HTTPSTATE_SEND_DATA;
2340 c->last_packet_sent = 0;
2342 case HTTPSTATE_SEND_DATA:
2343 /* find a new packet */
2344 /* read a packet from the input stream */
2345 if (c->stream->feed)
2346 ffm_set_write_index(c->fmt_in,
2347 c->stream->feed->feed_write_index,
2348 c->stream->feed->feed_size);
2350 if (c->stream->max_time &&
2351 c->stream->max_time + c->start_time - cur_time < 0)
2352 /* We have timed out */
2353 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2357 ret = av_read_frame(c->fmt_in, &pkt);
2359 if (c->stream->feed) {
2360 /* if coming from feed, it means we reached the end of the
2361 ffm file, so must wait for more data */
2362 c->state = HTTPSTATE_WAIT_FEED;
2363 return 1; /* state changed */
2364 } else if (ret == AVERROR(EAGAIN)) {
2365 /* input not ready, come back later */
2368 if (c->stream->loop) {
2369 avformat_close_input(&c->fmt_in);
2370 if (open_input_stream(c, "") < 0)
2375 /* must send trailer now because EOF or error */
2376 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2380 int source_index = pkt.stream_index;
2381 /* update first pts if needed */
2382 if (c->first_pts == AV_NOPTS_VALUE) {
2383 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2384 c->start_time = cur_time;
2386 /* send it to the appropriate stream */
2387 if (c->stream->feed) {
2388 /* if coming from a feed, select the right stream */
2389 if (c->switch_pending) {
2390 c->switch_pending = 0;
2391 for(i=0;i<c->stream->nb_streams;i++) {
2392 if (c->switch_feed_streams[i] == pkt.stream_index)
2393 if (pkt.flags & AV_PKT_FLAG_KEY)
2394 c->switch_feed_streams[i] = -1;
2395 if (c->switch_feed_streams[i] >= 0)
2396 c->switch_pending = 1;
2399 for(i=0;i<c->stream->nb_streams;i++) {
2400 if (c->stream->feed_streams[i] == pkt.stream_index) {
2401 AVStream *st = c->fmt_in->streams[source_index];
2402 pkt.stream_index = i;
2403 if (pkt.flags & AV_PKT_FLAG_KEY &&
2404 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2405 c->stream->nb_streams == 1))
2406 c->got_key_frame = 1;
2407 if (!c->stream->send_on_key || c->got_key_frame)
2412 AVCodecContext *codec;
2413 AVStream *ist, *ost;
2415 ist = c->fmt_in->streams[source_index];
2416 /* specific handling for RTP: we use several
2417 * output streams (one for each RTP connection).
2418 * XXX: need more abstract handling */
2419 if (c->is_packetized) {
2420 /* compute send time and duration */
2421 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2422 c->cur_pts -= c->first_pts;
2423 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2424 /* find RTP context */
2425 c->packet_stream_index = pkt.stream_index;
2426 ctx = c->rtp_ctx[c->packet_stream_index];
2428 av_free_packet(&pkt);
2431 codec = ctx->streams[0]->codec;
2432 /* only one stream per RTP connection */
2433 pkt.stream_index = 0;
2437 codec = ctx->streams[pkt.stream_index]->codec;
2440 if (c->is_packetized) {
2441 int max_packet_size;
2442 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2443 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2445 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2446 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2448 ret = avio_open_dyn_buf(&ctx->pb);
2451 /* XXX: potential leak */
2454 ost = ctx->streams[pkt.stream_index];
2456 ctx->pb->seekable = 0;
2457 if (pkt.dts != AV_NOPTS_VALUE)
2458 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2459 if (pkt.pts != AV_NOPTS_VALUE)
2460 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2461 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2462 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2463 http_log("Error writing frame to output for stream '%s': %s\n",
2464 c->stream->filename, av_err2str(ret));
2465 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2468 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2469 c->cur_frame_bytes = len;
2470 c->buffer_ptr = c->pb_buffer;
2471 c->buffer_end = c->pb_buffer + len;
2473 codec->frame_number++;
2475 av_free_packet(&pkt);
2479 av_free_packet(&pkt);
2484 case HTTPSTATE_SEND_DATA_TRAILER:
2485 /* last packet test ? */
2486 if (c->last_packet_sent || c->is_packetized)
2489 /* prepare header */
2490 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2491 /* XXX: potential leak */
2494 c->fmt_ctx.pb->seekable = 0;
2495 av_write_trailer(ctx);
2496 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2497 c->buffer_ptr = c->pb_buffer;
2498 c->buffer_end = c->pb_buffer + len;
2500 c->last_packet_sent = 1;
2506 /* should convert the format at the same time */
2507 /* send data starting at c->buffer_ptr to the output connection
2508 * (either UDP or TCP) */
2509 static int http_send_data(HTTPContext *c)
2514 if (c->buffer_ptr >= c->buffer_end) {
2515 ret = http_prepare_data(c);
2519 /* state change requested */
2522 if (c->is_packetized) {
2523 /* RTP data output */
2524 len = c->buffer_end - c->buffer_ptr;
2526 /* fail safe - should never happen */
2528 c->buffer_ptr = c->buffer_end;
2531 len = (c->buffer_ptr[0] << 24) |
2532 (c->buffer_ptr[1] << 16) |
2533 (c->buffer_ptr[2] << 8) |
2535 if (len > (c->buffer_end - c->buffer_ptr))
2537 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2538 /* nothing to send yet: we can wait */
2542 c->data_count += len;
2543 update_datarate(&c->datarate, c->data_count);
2545 c->stream->bytes_served += len;
2547 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2548 /* RTP packets are sent inside the RTSP TCP connection */
2550 int interleaved_index, size;
2552 HTTPContext *rtsp_c;
2555 /* if no RTSP connection left, error */
2558 /* if already sending something, then wait. */
2559 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2561 if (avio_open_dyn_buf(&pb) < 0)
2563 interleaved_index = c->packet_stream_index * 2;
2564 /* RTCP packets are sent at odd indexes */
2565 if (c->buffer_ptr[1] == 200)
2566 interleaved_index++;
2567 /* write RTSP TCP header */
2569 header[1] = interleaved_index;
2570 header[2] = len >> 8;
2572 avio_write(pb, header, 4);
2573 /* write RTP packet data */
2575 avio_write(pb, c->buffer_ptr, len);
2576 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2577 /* prepare asynchronous TCP sending */
2578 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2579 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2580 c->buffer_ptr += len;
2582 /* send everything we can NOW */
2583 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2584 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2586 rtsp_c->packet_buffer_ptr += len;
2587 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2588 /* if we could not send all the data, we will
2589 send it later, so a new state is needed to
2590 "lock" the RTSP TCP connection */
2591 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2594 /* all data has been sent */
2595 av_freep(&c->packet_buffer);
2597 /* send RTP packet directly in UDP */
2599 ffurl_write(c->rtp_handles[c->packet_stream_index],
2600 c->buffer_ptr, len);
2601 c->buffer_ptr += len;
2602 /* here we continue as we can send several packets per 10 ms slot */
2605 /* TCP data output */
2606 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2608 if (ff_neterrno() != AVERROR(EAGAIN) &&
2609 ff_neterrno() != AVERROR(EINTR))
2610 /* error : close connection */
2615 c->buffer_ptr += len;
2617 c->data_count += len;
2618 update_datarate(&c->datarate, c->data_count);
2620 c->stream->bytes_served += len;
2628 static int http_start_receive_data(HTTPContext *c)
2633 if (c->stream->feed_opened) {
2634 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2635 return AVERROR(EINVAL);
2638 /* Don't permit writing to this one */
2639 if (c->stream->readonly) {
2640 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2641 return AVERROR(EINVAL);
2645 fd = open(c->stream->feed_filename, O_RDWR);
2647 ret = AVERROR(errno);
2648 http_log("Could not open feed file '%s': %s\n",
2649 c->stream->feed_filename, strerror(errno));
2654 if (c->stream->truncate) {
2655 /* truncate feed file */
2656 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2657 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2658 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2659 ret = AVERROR(errno);
2660 http_log("Error truncating feed file '%s': %s\n",
2661 c->stream->feed_filename, strerror(errno));
2665 ret = ffm_read_write_index(fd);
2667 http_log("Error reading write index from feed file '%s': %s\n",
2668 c->stream->feed_filename, strerror(errno));
2671 c->stream->feed_write_index = ret;
2675 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2676 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2677 lseek(fd, 0, SEEK_SET);
2679 /* init buffer input */
2680 c->buffer_ptr = c->buffer;
2681 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2682 c->stream->feed_opened = 1;
2683 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2687 static int http_receive_data(HTTPContext *c)
2690 int len, loop_run = 0;
2692 while (c->chunked_encoding && !c->chunk_size &&
2693 c->buffer_end > c->buffer_ptr) {
2694 /* read chunk header, if present */
2695 len = recv(c->fd, c->buffer_ptr, 1, 0);
2698 if (ff_neterrno() != AVERROR(EAGAIN) &&
2699 ff_neterrno() != AVERROR(EINTR))
2700 /* error : close connection */
2703 } else if (len == 0) {
2704 /* end of connection : close it */
2706 } else if (c->buffer_ptr - c->buffer >= 2 &&
2707 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2708 c->chunk_size = strtol(c->buffer, 0, 16);
2709 if (c->chunk_size == 0) // end of stream
2711 c->buffer_ptr = c->buffer;
2713 } else if (++loop_run > 10) {
2714 /* no chunk header, abort */
2721 if (c->buffer_end > c->buffer_ptr) {
2722 len = recv(c->fd, c->buffer_ptr,
2723 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2725 if (ff_neterrno() != AVERROR(EAGAIN) &&
2726 ff_neterrno() != AVERROR(EINTR))
2727 /* error : close connection */
2729 } else if (len == 0)
2730 /* end of connection : close it */
2733 c->chunk_size -= len;
2734 c->buffer_ptr += len;
2735 c->data_count += len;
2736 update_datarate(&c->datarate, c->data_count);
2740 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2741 if (c->buffer[0] != 'f' ||
2742 c->buffer[1] != 'm') {
2743 http_log("Feed stream has become desynchronized -- disconnecting\n");
2748 if (c->buffer_ptr >= c->buffer_end) {
2749 FFStream *feed = c->stream;
2750 /* a packet has been received : write it in the store, except
2752 if (c->data_count > FFM_PACKET_SIZE) {
2753 /* XXX: use llseek or url_seek */
2754 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2755 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2756 http_log("Error writing to feed file: %s\n", strerror(errno));
2760 feed->feed_write_index += FFM_PACKET_SIZE;
2761 /* update file size */
2762 if (feed->feed_write_index > c->stream->feed_size)
2763 feed->feed_size = feed->feed_write_index;
2765 /* handle wrap around if max file size reached */
2766 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2767 feed->feed_write_index = FFM_PACKET_SIZE;
2770 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2771 http_log("Error writing index to feed file: %s\n", strerror(errno));
2775 /* wake up any waiting connections */
2776 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2777 if (c1->state == HTTPSTATE_WAIT_FEED &&
2778 c1->stream->feed == c->stream->feed)
2779 c1->state = HTTPSTATE_SEND_DATA;
2782 /* We have a header in our hands that contains useful data */
2783 AVFormatContext *s = avformat_alloc_context();
2785 AVInputFormat *fmt_in;
2791 /* use feed output format name to find corresponding input format */
2792 fmt_in = av_find_input_format(feed->fmt->name);
2796 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2797 0, NULL, NULL, NULL, NULL);
2801 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2806 /* Now we have the actual streams */
2807 if (s->nb_streams != feed->nb_streams) {
2808 avformat_close_input(&s);
2810 http_log("Feed '%s' stream number does not match registered feed\n",
2811 c->stream->feed_filename);
2815 for (i = 0; i < s->nb_streams; i++) {
2816 AVStream *fst = feed->streams[i];
2817 AVStream *st = s->streams[i];
2818 avcodec_copy_context(fst->codec, st->codec);
2821 avformat_close_input(&s);
2824 c->buffer_ptr = c->buffer;
2829 c->stream->feed_opened = 0;
2831 /* wake up any waiting connections to stop waiting for feed */
2832 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2833 if (c1->state == HTTPSTATE_WAIT_FEED &&
2834 c1->stream->feed == c->stream->feed)
2835 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2840 /********************************************************************/
2843 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2850 str = RTSP_STATUS_CODE2STRING(error_number);
2852 str = "Unknown Error";
2854 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2855 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2857 /* output GMT time */
2860 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2861 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2864 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2866 rtsp_reply_header(c, error_number);
2867 avio_printf(c->pb, "\r\n");
2870 static int rtsp_parse_request(HTTPContext *c)
2872 const char *p, *p1, *p2;
2878 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2880 c->buffer_ptr[0] = '\0';
2883 get_word(cmd, sizeof(cmd), &p);
2884 get_word(url, sizeof(url), &p);
2885 get_word(protocol, sizeof(protocol), &p);
2887 av_strlcpy(c->method, cmd, sizeof(c->method));
2888 av_strlcpy(c->url, url, sizeof(c->url));
2889 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2891 if (avio_open_dyn_buf(&c->pb) < 0) {
2892 /* XXX: cannot do more */
2893 c->pb = NULL; /* safety */
2897 /* check version name */
2898 if (strcmp(protocol, "RTSP/1.0") != 0) {
2899 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2903 /* parse each header line */
2904 /* skip to next line */
2905 while (*p != '\n' && *p != '\0')
2909 while (*p != '\0') {
2910 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2914 if (p2 > p && p2[-1] == '\r')
2916 /* skip empty line */
2920 if (len > sizeof(line) - 1)
2921 len = sizeof(line) - 1;
2922 memcpy(line, p, len);
2924 ff_rtsp_parse_line(header, line, NULL, NULL);
2928 /* handle sequence number */
2929 c->seq = header->seq;
2931 if (!strcmp(cmd, "DESCRIBE"))
2932 rtsp_cmd_describe(c, url);
2933 else if (!strcmp(cmd, "OPTIONS"))
2934 rtsp_cmd_options(c, url);
2935 else if (!strcmp(cmd, "SETUP"))
2936 rtsp_cmd_setup(c, url, header);
2937 else if (!strcmp(cmd, "PLAY"))
2938 rtsp_cmd_play(c, url, header);
2939 else if (!strcmp(cmd, "PAUSE"))
2940 rtsp_cmd_interrupt(c, url, header, 1);
2941 else if (!strcmp(cmd, "TEARDOWN"))
2942 rtsp_cmd_interrupt(c, url, header, 0);
2944 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2947 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2948 c->pb = NULL; /* safety */
2950 /* XXX: cannot do more */
2953 c->buffer_ptr = c->pb_buffer;
2954 c->buffer_end = c->pb_buffer + len;
2955 c->state = RTSPSTATE_SEND_REPLY;
2959 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2960 struct in_addr my_ip)
2962 AVFormatContext *avc;
2963 AVStream *avs = NULL;
2964 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2965 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2968 avc = avformat_alloc_context();
2969 if (avc == NULL || !rtp_format) {
2972 avc->oformat = rtp_format;
2973 av_dict_set(&avc->metadata, "title",
2974 entry ? entry->value : "No Title", 0);
2975 avc->nb_streams = stream->nb_streams;
2976 if (stream->is_multicast) {
2977 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2978 inet_ntoa(stream->multicast_ip),
2979 stream->multicast_port, stream->multicast_ttl);
2981 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2984 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2985 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2987 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2988 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2991 for(i = 0; i < stream->nb_streams; i++) {
2992 avc->streams[i] = &avs[i];
2993 avc->streams[i]->codec = stream->streams[i]->codec;
2995 *pbuffer = av_mallocz(2048);
2996 av_sdp_create(&avc, 1, *pbuffer, 2048);
2999 av_free(avc->streams);
3000 av_dict_free(&avc->metadata);
3004 return strlen(*pbuffer);
3007 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3009 // rtsp_reply_header(c, RTSP_STATUS_OK);
3010 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3011 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3012 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3013 avio_printf(c->pb, "\r\n");
3016 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3024 struct sockaddr_in my_addr;
3026 /* find which URL is asked */
3027 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3032 for(stream = first_stream; stream != NULL; stream = stream->next) {
3033 if (!stream->is_feed &&
3034 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3035 !strcmp(path, stream->filename)) {
3039 /* no stream found */
3040 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3044 /* prepare the media description in SDP format */
3046 /* get the host IP */
3047 len = sizeof(my_addr);
3048 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3049 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3050 if (content_length < 0) {
3051 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3054 rtsp_reply_header(c, RTSP_STATUS_OK);
3055 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3056 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3057 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3058 avio_printf(c->pb, "\r\n");
3059 avio_write(c->pb, content, content_length);
3063 static HTTPContext *find_rtp_session(const char *session_id)
3067 if (session_id[0] == '\0')
3070 for(c = first_http_ctx; c != NULL; c = c->next) {
3071 if (!strcmp(c->session_id, session_id))
3077 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3079 RTSPTransportField *th;
3082 for(i=0;i<h->nb_transports;i++) {
3083 th = &h->transports[i];
3084 if (th->lower_transport == lower_transport)
3090 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3091 RTSPMessageHeader *h)
3094 int stream_index, rtp_port, rtcp_port;
3099 RTSPTransportField *th;
3100 struct sockaddr_in dest_addr;
3101 RTSPActionServerSetup setup;
3103 /* find which URL is asked */
3104 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3109 /* now check each stream */
3110 for(stream = first_stream; stream != NULL; stream = stream->next) {
3111 if (!stream->is_feed &&
3112 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3113 /* accept aggregate filenames only if single stream */
3114 if (!strcmp(path, stream->filename)) {
3115 if (stream->nb_streams != 1) {
3116 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3123 for(stream_index = 0; stream_index < stream->nb_streams;
3125 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3126 stream->filename, stream_index);
3127 if (!strcmp(path, buf))
3132 /* no stream found */
3133 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3137 /* generate session id if needed */
3138 if (h->session_id[0] == '\0') {
3139 unsigned random0 = av_lfg_get(&random_state);
3140 unsigned random1 = av_lfg_get(&random_state);
3141 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3145 /* find RTP session, and create it if none found */
3146 rtp_c = find_rtp_session(h->session_id);
3148 /* always prefer UDP */
3149 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3151 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3153 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3158 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3159 th->lower_transport);
3161 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3165 /* open input stream */
3166 if (open_input_stream(rtp_c, "") < 0) {
3167 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3172 /* test if stream is OK (test needed because several SETUP needs
3173 to be done for a given file) */
3174 if (rtp_c->stream != stream) {
3175 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3179 /* test if stream is already set up */
3180 if (rtp_c->rtp_ctx[stream_index]) {
3181 rtsp_reply_error(c, RTSP_STATUS_STATE);
3185 /* check transport */
3186 th = find_transport(h, rtp_c->rtp_protocol);
3187 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3188 th->client_port_min <= 0)) {
3189 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3193 /* setup default options */
3194 setup.transport_option[0] = '\0';
3195 dest_addr = rtp_c->from_addr;
3196 dest_addr.sin_port = htons(th->client_port_min);
3199 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3200 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3204 /* now everything is OK, so we can send the connection parameters */
3205 rtsp_reply_header(c, RTSP_STATUS_OK);
3207 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3209 switch(rtp_c->rtp_protocol) {
3210 case RTSP_LOWER_TRANSPORT_UDP:
3211 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3212 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3213 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3214 "client_port=%d-%d;server_port=%d-%d",
3215 th->client_port_min, th->client_port_max,
3216 rtp_port, rtcp_port);
3218 case RTSP_LOWER_TRANSPORT_TCP:
3219 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3220 stream_index * 2, stream_index * 2 + 1);
3225 if (setup.transport_option[0] != '\0')
3226 avio_printf(c->pb, ";%s", setup.transport_option);
3227 avio_printf(c->pb, "\r\n");
3230 avio_printf(c->pb, "\r\n");
3234 /* find an RTP connection by using the session ID. Check consistency
3236 static HTTPContext *find_rtp_session_with_url(const char *url,
3237 const char *session_id)
3245 rtp_c = find_rtp_session(session_id);
3249 /* find which URL is asked */
3250 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3254 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3255 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3256 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3257 rtp_c->stream->filename, s);
3258 if(!strncmp(path, buf, sizeof(buf))) {
3259 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3264 if (len > 0 && path[len - 1] == '/' &&
3265 !strncmp(path, rtp_c->stream->filename, len - 1))
3270 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3274 rtp_c = find_rtp_session_with_url(url, h->session_id);
3276 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3280 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3281 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3282 rtp_c->state != HTTPSTATE_READY) {
3283 rtsp_reply_error(c, RTSP_STATUS_STATE);
3287 rtp_c->state = HTTPSTATE_SEND_DATA;
3289 /* now everything is OK, so we can send the connection parameters */
3290 rtsp_reply_header(c, RTSP_STATUS_OK);
3292 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3293 avio_printf(c->pb, "\r\n");
3296 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3300 rtp_c = find_rtp_session_with_url(url, h->session_id);
3302 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3307 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3308 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3309 rtsp_reply_error(c, RTSP_STATUS_STATE);
3312 rtp_c->state = HTTPSTATE_READY;
3313 rtp_c->first_pts = AV_NOPTS_VALUE;
3316 /* now everything is OK, so we can send the connection parameters */
3317 rtsp_reply_header(c, RTSP_STATUS_OK);
3319 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3320 avio_printf(c->pb, "\r\n");
3323 close_connection(rtp_c);
3326 /********************************************************************/
3329 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3330 FFStream *stream, const char *session_id,
3331 enum RTSPLowerTransport rtp_protocol)
3333 HTTPContext *c = NULL;
3334 const char *proto_str;
3336 /* XXX: should output a warning page when coming
3337 close to the connection limit */
3338 if (nb_connections >= nb_max_connections)
3341 /* add a new connection */
3342 c = av_mallocz(sizeof(HTTPContext));
3347 c->poll_entry = NULL;
3348 c->from_addr = *from_addr;
3349 c->buffer_size = IOBUFFER_INIT_SIZE;
3350 c->buffer = av_malloc(c->buffer_size);
3355 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3356 c->state = HTTPSTATE_READY;
3357 c->is_packetized = 1;
3358 c->rtp_protocol = rtp_protocol;
3360 /* protocol is shown in statistics */
3361 switch(c->rtp_protocol) {
3362 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3363 proto_str = "MCAST";
3365 case RTSP_LOWER_TRANSPORT_UDP:
3368 case RTSP_LOWER_TRANSPORT_TCP:
3375 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3376 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3378 current_bandwidth += stream->bandwidth;
3380 c->next = first_http_ctx;
3392 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3393 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3395 static int rtp_new_av_stream(HTTPContext *c,
3396 int stream_index, struct sockaddr_in *dest_addr,
3397 HTTPContext *rtsp_c)
3399 AVFormatContext *ctx;
3402 URLContext *h = NULL;
3404 int max_packet_size;
3406 /* now we can open the relevant output stream */
3407 ctx = avformat_alloc_context();
3410 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3412 st = av_mallocz(sizeof(AVStream));
3415 ctx->nb_streams = 1;
3416 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3419 ctx->streams[0] = st;
3421 if (!c->stream->feed ||
3422 c->stream->feed == c->stream)
3423 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3426 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3428 st->priv_data = NULL;
3430 /* build destination RTP address */
3431 ipaddr = inet_ntoa(dest_addr->sin_addr);
3433 switch(c->rtp_protocol) {
3434 case RTSP_LOWER_TRANSPORT_UDP:
3435 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3438 /* XXX: also pass as parameter to function ? */
3439 if (c->stream->is_multicast) {
3441 ttl = c->stream->multicast_ttl;
3444 snprintf(ctx->filename, sizeof(ctx->filename),
3445 "rtp://%s:%d?multicast=1&ttl=%d",
3446 ipaddr, ntohs(dest_addr->sin_port), ttl);
3448 snprintf(ctx->filename, sizeof(ctx->filename),
3449 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3452 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3454 c->rtp_handles[stream_index] = h;
3455 max_packet_size = h->max_packet_size;
3457 case RTSP_LOWER_TRANSPORT_TCP:
3460 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3466 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3467 ipaddr, ntohs(dest_addr->sin_port),
3468 c->stream->filename, stream_index, c->protocol);
3470 /* normally, no packets should be output here, but the packet size may
3472 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3473 /* XXX: close stream */
3476 if (avformat_write_header(ctx, NULL) < 0) {
3484 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3487 c->rtp_ctx[stream_index] = ctx;
3491 /********************************************************************/
3492 /* ffserver initialization */
3494 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3498 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3501 fst = av_mallocz(sizeof(AVStream));
3505 fst->codec = avcodec_alloc_context3(NULL);
3506 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3507 if (codec->extradata_size) {
3508 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3509 memcpy(fst->codec->extradata, codec->extradata,
3510 codec->extradata_size);
3513 /* live streams must use the actual feed's codec since it may be
3514 * updated later to carry extradata needed by them.
3518 fst->priv_data = av_mallocz(sizeof(FeedData));
3519 fst->index = stream->nb_streams;
3520 avpriv_set_pts_info(fst, 33, 1, 90000);
3521 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3522 stream->streams[stream->nb_streams++] = fst;
3526 /* return the stream number in the feed */
3527 static int add_av_stream(FFStream *feed, AVStream *st)
3530 AVCodecContext *av, *av1;
3534 for(i=0;i<feed->nb_streams;i++) {
3535 st = feed->streams[i];
3537 if (av1->codec_id == av->codec_id &&
3538 av1->codec_type == av->codec_type &&
3539 av1->bit_rate == av->bit_rate) {
3541 switch(av->codec_type) {
3542 case AVMEDIA_TYPE_AUDIO:
3543 if (av1->channels == av->channels &&
3544 av1->sample_rate == av->sample_rate)
3547 case AVMEDIA_TYPE_VIDEO:
3548 if (av1->width == av->width &&
3549 av1->height == av->height &&
3550 av1->time_base.den == av->time_base.den &&
3551 av1->time_base.num == av->time_base.num &&
3552 av1->gop_size == av->gop_size)
3561 fst = add_av_stream1(feed, av, 0);
3564 return feed->nb_streams - 1;
3567 static void remove_stream(FFStream *stream)
3571 while (*ps != NULL) {
3579 /* specific MPEG4 handling : we extract the raw parameters */
3580 static void extract_mpeg4_header(AVFormatContext *infile)
3582 int mpeg4_count, i, size;
3587 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3590 for(i=0;i<infile->nb_streams;i++) {
3591 st = infile->streams[i];
3592 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3593 st->codec->extradata_size == 0) {
3600 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3601 while (mpeg4_count > 0) {
3602 if (av_read_frame(infile, &pkt) < 0)
3604 st = infile->streams[pkt.stream_index];
3605 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3606 st->codec->extradata_size == 0) {
3607 av_freep(&st->codec->extradata);
3608 /* fill extradata with the header */
3609 /* XXX: we make hard suppositions here ! */
3611 while (p < pkt.data + pkt.size - 4) {
3612 /* stop when vop header is found */
3613 if (p[0] == 0x00 && p[1] == 0x00 &&
3614 p[2] == 0x01 && p[3] == 0xb6) {
3615 size = p - pkt.data;
3616 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3617 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3618 st->codec->extradata_size = size;
3619 memcpy(st->codec->extradata, pkt.data, size);
3626 av_free_packet(&pkt);
3630 /* compute the needed AVStream for each file */
3631 static void build_file_streams(void)
3633 FFStream *stream, *stream_next;
3636 /* gather all streams */
3637 for(stream = first_stream; stream != NULL; stream = stream_next) {
3638 AVFormatContext *infile = NULL;
3639 stream_next = stream->next;
3640 if (stream->stream_type == STREAM_TYPE_LIVE &&
3642 /* the stream comes from a file */
3643 /* try to open the file */
3645 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3646 /* specific case : if transport stream output to RTP,
3647 we use a raw transport stream reader */
3648 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3651 if (!stream->feed_filename[0]) {
3652 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3656 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3657 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3658 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3659 /* remove stream (no need to spend more time on it) */
3661 remove_stream(stream);
3663 /* find all the AVStreams inside and reference them in
3665 if (avformat_find_stream_info(infile, NULL) < 0) {
3666 http_log("Could not find codec parameters from '%s'\n",
3667 stream->feed_filename);
3668 avformat_close_input(&infile);
3671 extract_mpeg4_header(infile);
3673 for(i=0;i<infile->nb_streams;i++)
3674 add_av_stream1(stream, infile->streams[i]->codec, 1);
3676 avformat_close_input(&infile);
3682 /* compute the needed AVStream for each feed */
3683 static void build_feed_streams(void)
3685 FFStream *stream, *feed;
3688 /* gather all streams */
3689 for(stream = first_stream; stream != NULL; stream = stream->next) {
3690 feed = stream->feed;
3692 if (stream->is_feed) {
3693 for(i=0;i<stream->nb_streams;i++)
3694 stream->feed_streams[i] = i;
3696 /* we handle a stream coming from a feed */
3697 for(i=0;i<stream->nb_streams;i++)
3698 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3703 /* create feed files if needed */
3704 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3707 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3708 /* See if it matches */
3709 AVFormatContext *s = NULL;
3712 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3713 /* set buffer size */
3714 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3715 /* Now see if it matches */
3716 if (s->nb_streams == feed->nb_streams) {
3718 for(i=0;i<s->nb_streams;i++) {
3720 sf = feed->streams[i];
3723 if (sf->index != ss->index ||
3725 http_log("Index & Id do not match for stream %d (%s)\n",
3726 i, feed->feed_filename);
3729 AVCodecContext *ccf, *ccs;
3733 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3735 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3736 http_log("Codecs do not match for stream %d\n", i);
3738 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3739 http_log("Codec bitrates do not match for stream %d\n", i);
3741 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3742 if (CHECK_CODEC(time_base.den) ||
3743 CHECK_CODEC(time_base.num) ||
3744 CHECK_CODEC(width) ||
3745 CHECK_CODEC(height)) {
3746 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3749 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3750 if (CHECK_CODEC(sample_rate) ||
3751 CHECK_CODEC(channels) ||
3752 CHECK_CODEC(frame_size)) {
3753 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3757 http_log("Unknown codec type\n");
3765 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3766 feed->feed_filename, s->nb_streams, feed->nb_streams);
3768 avformat_close_input(&s);
3770 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3771 feed->feed_filename);
3774 if (feed->readonly) {
3775 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3776 feed->feed_filename);
3779 unlink(feed->feed_filename);
3782 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3783 AVFormatContext *s = avformat_alloc_context();
3785 if (feed->readonly) {
3786 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3787 feed->feed_filename);
3791 /* only write the header of the ffm file */
3792 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3793 http_log("Could not open output feed file '%s'\n",
3794 feed->feed_filename);
3797 s->oformat = feed->fmt;
3798 s->nb_streams = feed->nb_streams;
3799 s->streams = feed->streams;
3800 if (avformat_write_header(s, NULL) < 0) {
3801 http_log("Container doesn't support the required parameters\n");
3804 /* XXX: need better API */
3805 av_freep(&s->priv_data);
3809 avformat_free_context(s);
3811 /* get feed size and write index */
3812 fd = open(feed->feed_filename, O_RDONLY);
3814 http_log("Could not open output feed file '%s'\n",
3815 feed->feed_filename);
3819 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3820 feed->feed_size = lseek(fd, 0, SEEK_END);
3821 /* ensure that we do not wrap before the end of file */
3822 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3823 feed->feed_max_size = feed->feed_size;
3829 /* compute the bandwidth used by each stream */
3830 static void compute_bandwidth(void)
3836 for(stream = first_stream; stream != NULL; stream = stream->next) {
3838 for(i=0;i<stream->nb_streams;i++) {
3839 AVStream *st = stream->streams[i];
3840 switch(st->codec->codec_type) {
3841 case AVMEDIA_TYPE_AUDIO:
3842 case AVMEDIA_TYPE_VIDEO:
3843 bandwidth += st->codec->bit_rate;
3849 stream->bandwidth = (bandwidth + 999) / 1000;
3853 /* add a codec and set the default parameters */
3854 static void add_codec(FFStream *stream, AVCodecContext *av)
3858 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3861 /* compute default parameters */
3862 switch(av->codec_type) {
3863 case AVMEDIA_TYPE_AUDIO:
3864 if (av->bit_rate == 0)
3865 av->bit_rate = 64000;
3866 if (av->sample_rate == 0)
3867 av->sample_rate = 22050;
3868 if (av->channels == 0)
3871 case AVMEDIA_TYPE_VIDEO:
3872 if (av->bit_rate == 0)
3873 av->bit_rate = 64000;
3874 if (av->time_base.num == 0){
3875 av->time_base.den = 5;
3876 av->time_base.num = 1;
3878 if (av->width == 0 || av->height == 0) {
3882 /* Bitrate tolerance is less for streaming */
3883 if (av->bit_rate_tolerance == 0)
3884 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3885 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3890 if (av->max_qdiff == 0)
3892 av->qcompress = 0.5;
3895 if (!av->nsse_weight)
3896 av->nsse_weight = 8;
3898 av->frame_skip_cmp = FF_CMP_DCTMAX;
3900 av->me_method = ME_EPZS;
3901 av->rc_buffer_aggressivity = 1.0;
3904 av->rc_eq = av_strdup("tex^qComp");
3905 if (!av->i_quant_factor)
3906 av->i_quant_factor = -0.8;
3907 if (!av->b_quant_factor)
3908 av->b_quant_factor = 1.25;
3909 if (!av->b_quant_offset)
3910 av->b_quant_offset = 1.25;
3911 if (!av->rc_max_rate)
3912 av->rc_max_rate = av->bit_rate * 2;
3914 if (av->rc_max_rate && !av->rc_buffer_size) {
3915 av->rc_buffer_size = av->rc_max_rate;
3924 st = av_mallocz(sizeof(AVStream));
3927 st->codec = avcodec_alloc_context3(NULL);
3928 stream->streams[stream->nb_streams++] = st;
3929 memcpy(st->codec, av, sizeof(AVCodecContext));
3932 static enum AVCodecID opt_codec(const char *name, enum AVMediaType type)
3934 AVCodec *codec = avcodec_find_encoder_by_name(name);
3936 if (!codec || codec->type != type)
3937 return AV_CODEC_ID_NONE;
3941 static int ffserver_opt_default(const char *opt, const char *arg,
3942 AVCodecContext *avctx, int type)
3945 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3947 ret = av_opt_set(avctx, opt, arg, 0);
3951 static int ffserver_opt_preset(const char *arg,
3952 AVCodecContext *avctx, int type,
3953 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3956 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3958 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3960 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3961 codec ? codec->name : NULL))) {
3962 fprintf(stderr, "File for preset '%s' not found\n", arg);
3967 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3968 if(line[0] == '#' && !e)
3970 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3972 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3976 if(!strcmp(tmp, "acodec")){
3977 *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
3978 }else if(!strcmp(tmp, "vcodec")){
3979 *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
3980 }else if(!strcmp(tmp, "scodec")){
3981 /* opt_subtitle_codec(tmp2); */
3982 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3983 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3994 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename, const char *mime_type)
3996 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3999 AVOutputFormat *stream_fmt;
4000 char stream_format_name[64];
4002 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4003 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4012 static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...)
4016 av_log(NULL, log_level, "%s:%d: ", filename, line_num);
4017 av_vlog(NULL, log_level, fmt, vl);
4023 static int parse_ffconfig(const char *filename)
4028 char arg[1024], arg2[1024];
4030 int val, errors, warnings, line_num;
4031 FFStream **last_stream, *stream, *redirect;
4032 FFStream **last_feed, *feed, *s;
4033 AVCodecContext audio_enc, video_enc;
4034 enum AVCodecID audio_id, video_id;
4037 f = fopen(filename, "r");
4039 ret = AVERROR(errno);
4040 av_log(NULL, AV_LOG_ERROR, "Could not open the configuration file '%s'\n", filename);
4044 errors = warnings = 0;
4046 first_stream = NULL;
4047 last_stream = &first_stream;
4049 last_feed = &first_feed;
4053 audio_id = AV_CODEC_ID_NONE;
4054 video_id = AV_CODEC_ID_NONE;
4055 #define ERROR(...) report_config_error(filename, line_num, AV_LOG_ERROR, &errors, __VA_ARGS__)
4056 #define WARNING(...) report_config_error(filename, line_num, AV_LOG_WARNING, &warnings, __VA_ARGS__)
4059 if (fgets(line, sizeof(line), f) == NULL)
4063 while (av_isspace(*p))
4065 if (*p == '\0' || *p == '#')
4068 get_arg(cmd, sizeof(cmd), &p);
4070 if (!av_strcasecmp(cmd, "Port")) {
4071 get_arg(arg, sizeof(arg), &p);
4073 if (val < 1 || val > 65536) {
4074 ERROR("Invalid_port: %s\n", arg);
4076 my_http_addr.sin_port = htons(val);
4077 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4078 get_arg(arg, sizeof(arg), &p);
4079 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4080 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4082 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4083 WARNING("NoDaemon option has no effect, you should remove it\n");
4084 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4085 get_arg(arg, sizeof(arg), &p);
4087 if (val < 1 || val > 65536) {
4088 ERROR("%s:%d: Invalid port: %s\n", arg);
4090 my_rtsp_addr.sin_port = htons(atoi(arg));
4091 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4092 get_arg(arg, sizeof(arg), &p);
4093 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4094 ERROR("Invalid host/IP address: %s\n", arg);
4096 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4097 get_arg(arg, sizeof(arg), &p);
4099 if (val < 1 || val > 65536) {
4100 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4102 nb_max_http_connections = val;
4103 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4104 get_arg(arg, sizeof(arg), &p);
4106 if (val < 1 || val > nb_max_http_connections) {
4107 ERROR("Invalid MaxClients: %s\n", arg);
4109 nb_max_connections = val;
4111 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4113 get_arg(arg, sizeof(arg), &p);
4114 llval = strtoll(arg, NULL, 10);
4115 if (llval < 10 || llval > 10000000) {
4116 ERROR("Invalid MaxBandwidth: %s\n", arg);
4118 max_bandwidth = llval;
4119 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4120 if (!ffserver_debug)
4121 get_arg(logfilename, sizeof(logfilename), &p);
4122 } else if (!av_strcasecmp(cmd, "<Feed")) {
4123 /*********************************************/
4124 /* Feed related options */
4126 if (stream || feed) {
4127 ERROR("Already in a tag\n");
4129 feed = av_mallocz(sizeof(FFStream));
4131 ret = AVERROR(ENOMEM);
4134 get_arg(feed->filename, sizeof(feed->filename), &p);
4135 q = strrchr(feed->filename, '>');
4139 for (s = first_feed; s; s = s->next) {
4140 if (!strcmp(feed->filename, s->filename)) {
4141 ERROR("Feed '%s' already registered\n", s->filename);
4145 feed->fmt = av_guess_format("ffm", NULL, NULL);
4146 /* default feed file */
4147 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4148 "/tmp/%s.ffm", feed->filename);
4149 feed->feed_max_size = 5 * 1024 * 1024;
4151 feed->feed = feed; /* self feeding :-) */
4153 /* add in stream list */
4154 *last_stream = feed;
4155 last_stream = &feed->next;
4156 /* add in feed list */
4158 last_feed = &feed->next_feed;
4160 } else if (!av_strcasecmp(cmd, "Launch")) {
4164 feed->child_argv = av_mallocz(64 * sizeof(char *));
4165 if (!feed->child_argv) {
4166 ret = AVERROR(ENOMEM);
4169 for (i = 0; i < 62; i++) {
4170 get_arg(arg, sizeof(arg), &p);
4174 feed->child_argv[i] = av_strdup(arg);
4175 if (!feed->child_argv[i]) {
4176 ret = AVERROR(ENOMEM);
4181 feed->child_argv[i] =
4182 av_asprintf("http://%s:%d/%s",
4183 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4184 inet_ntoa(my_http_addr.sin_addr), ntohs(my_http_addr.sin_port),
4186 if (!feed->child_argv[i]) {
4187 ret = AVERROR(ENOMEM);
4191 } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
4193 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4194 feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile");
4195 } else if (stream) {
4196 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4198 } else if (!av_strcasecmp(cmd, "Truncate")) {
4200 get_arg(arg, sizeof(arg), &p);
4201 /* assume Truncate is true in case no argument is specified */
4205 WARNING("Truncate N syntax in configuration file is deprecated, "
4206 "use Truncate alone with no arguments\n");
4207 feed->truncate = strtod(arg, NULL);
4210 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4215 get_arg(arg, sizeof(arg), &p);
4217 fsize = strtod(p1, &p1);
4218 switch(av_toupper(*p1)) {
4223 fsize *= 1024 * 1024;
4226 fsize *= 1024 * 1024 * 1024;
4229 feed->feed_max_size = (int64_t)fsize;
4230 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4231 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4234 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4236 ERROR("No corresponding <Feed> for </Feed>\n");
4239 } else if (!av_strcasecmp(cmd, "<Stream")) {
4240 /*********************************************/
4241 /* Stream related options */
4243 if (stream || feed) {
4244 ERROR("Already in a tag\n");
4247 stream = av_mallocz(sizeof(FFStream));
4249 ret = AVERROR(ENOMEM);
4252 get_arg(stream->filename, sizeof(stream->filename), &p);
4253 q = strrchr(stream->filename, '>');
4257 for (s = first_stream; s; s = s->next) {
4258 if (!strcmp(stream->filename, s->filename)) {
4259 ERROR("Stream '%s' already registered\n", s->filename);
4263 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4264 avcodec_get_context_defaults3(&video_enc, NULL);
4265 avcodec_get_context_defaults3(&audio_enc, NULL);
4267 audio_id = AV_CODEC_ID_NONE;
4268 video_id = AV_CODEC_ID_NONE;
4270 audio_id = stream->fmt->audio_codec;
4271 video_id = stream->fmt->video_codec;
4274 *last_stream = stream;
4275 last_stream = &stream->next;
4277 } else if (!av_strcasecmp(cmd, "Feed")) {
4278 get_arg(arg, sizeof(arg), &p);
4283 while (sfeed != NULL) {
4284 if (!strcmp(sfeed->filename, arg))
4286 sfeed = sfeed->next_feed;
4289 ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg, stream->filename);
4291 stream->feed = sfeed;
4293 } else if (!av_strcasecmp(cmd, "Format")) {
4294 get_arg(arg, sizeof(arg), &p);
4296 if (!strcmp(arg, "status")) {
4297 stream->stream_type = STREAM_TYPE_STATUS;
4300 stream->stream_type = STREAM_TYPE_LIVE;
4301 /* JPEG cannot be used here, so use single frame MJPEG */
4302 if (!strcmp(arg, "jpeg"))
4303 strcpy(arg, "mjpeg");
4304 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4306 ERROR("Unknown Format: %s\n", arg);
4310 audio_id = stream->fmt->audio_codec;
4311 video_id = stream->fmt->video_codec;
4314 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4315 get_arg(arg, sizeof(arg), &p);
4317 stream->ifmt = av_find_input_format(arg);
4318 if (!stream->ifmt) {
4319 ERROR("Unknown input format: %s\n", arg);
4322 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4323 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4324 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4326 ERROR("FaviconURL only permitted for status streams\n");
4328 } else if (!av_strcasecmp(cmd, "Author") ||
4329 !av_strcasecmp(cmd, "Comment") ||
4330 !av_strcasecmp(cmd, "Copyright") ||
4331 !av_strcasecmp(cmd, "Title")) {
4332 get_arg(arg, sizeof(arg), &p);
4338 for (i = 0; i < strlen(cmd); i++)
4339 key[i] = av_tolower(cmd[i]);
4341 WARNING("'%s' option in configuration file is deprecated, "
4342 "use 'Metadata %s VALUE' instead\n", cmd, key);
4343 if ((ret = av_dict_set(&stream->metadata, key, arg, 0)) < 0) {
4344 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4345 key, arg, av_err2str(ret));
4348 } else if (!av_strcasecmp(cmd, "Metadata")) {
4349 get_arg(arg, sizeof(arg), &p);
4350 get_arg(arg2, sizeof(arg2), &p);
4353 if ((ret = av_dict_set(&stream->metadata, arg, arg2, 0)) < 0) {
4354 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4355 arg, arg2, av_err2str(ret));
4358 } else if (!av_strcasecmp(cmd, "Preroll")) {
4359 get_arg(arg, sizeof(arg), &p);
4361 stream->prebuffer = atof(arg) * 1000;
4362 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4364 stream->send_on_key = 1;
4365 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4366 get_arg(arg, sizeof(arg), &p);
4367 audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO);
4368 if (audio_id == AV_CODEC_ID_NONE) {
4369 ERROR("Unknown AudioCodec: %s\n", arg);
4371 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4372 get_arg(arg, sizeof(arg), &p);
4373 video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO);
4374 if (video_id == AV_CODEC_ID_NONE) {
4375 ERROR("Unknown VideoCodec: %s\n", arg);
4377 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4378 get_arg(arg, sizeof(arg), &p);
4380 stream->max_time = atof(arg) * 1000;
4381 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4382 get_arg(arg, sizeof(arg), &p);
4384 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4385 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4386 get_arg(arg, sizeof(arg), &p);
4388 audio_enc.channels = atoi(arg);
4389 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4390 get_arg(arg, sizeof(arg), &p);
4392 audio_enc.sample_rate = atoi(arg);
4393 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4395 int minrate, maxrate;
4397 get_arg(arg, sizeof(arg), &p);
4399 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4400 video_enc.rc_min_rate = minrate * 1000;
4401 video_enc.rc_max_rate = maxrate * 1000;
4403 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4406 } else if (!av_strcasecmp(cmd, "Debug")) {
4408 get_arg(arg, sizeof(arg), &p);
4409 video_enc.debug = strtol(arg,0,0);
4411 } else if (!av_strcasecmp(cmd, "Strict")) {
4413 get_arg(arg, sizeof(arg), &p);
4414 video_enc.strict_std_compliance = atoi(arg);
4416 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4418 get_arg(arg, sizeof(arg), &p);
4419 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4421 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4423 get_arg(arg, sizeof(arg), &p);
4424 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4426 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4427 get_arg(arg, sizeof(arg), &p);
4429 video_enc.bit_rate = atoi(arg) * 1000;
4431 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4432 get_arg(arg, sizeof(arg), &p);
4434 ret = av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4436 ERROR("Invalid video size '%s'\n", arg);
4438 if ((video_enc.width % 16) != 0 ||
4439 (video_enc.height % 16) != 0) {
4440 ERROR("Image size must be a multiple of 16\n");
4444 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4445 get_arg(arg, sizeof(arg), &p);
4447 AVRational frame_rate;
4448 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4449 ERROR("Incorrect frame rate: %s\n", arg);
4451 video_enc.time_base.num = frame_rate.den;
4452 video_enc.time_base.den = frame_rate.num;
4455 } else if (!av_strcasecmp(cmd, "PixelFormat")) {
4456 get_arg(arg, sizeof(arg), &p);
4458 video_enc.pix_fmt = av_get_pix_fmt(arg);
4459 if (video_enc.pix_fmt == AV_PIX_FMT_NONE) {
4460 ERROR("Unknown pixel format: %s\n", arg);
4463 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4464 get_arg(arg, sizeof(arg), &p);
4466 video_enc.gop_size = atoi(arg);
4467 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4469 video_enc.gop_size = 1;
4470 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4472 video_enc.mb_decision = FF_MB_DECISION_BITS;
4473 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4475 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4476 video_enc.flags |= CODEC_FLAG_4MV;
4478 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4479 !av_strcasecmp(cmd, "AVOptionAudio")) {
4480 AVCodecContext *avctx;
4482 get_arg(arg, sizeof(arg), &p);
4483 get_arg(arg2, sizeof(arg2), &p);
4484 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4486 type = AV_OPT_FLAG_VIDEO_PARAM;
4489 type = AV_OPT_FLAG_AUDIO_PARAM;
4491 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4492 ERROR("Error setting %s option to %s %s\n", cmd, arg, arg2);
4494 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4495 !av_strcasecmp(cmd, "AVPresetAudio")) {
4496 AVCodecContext *avctx;
4498 get_arg(arg, sizeof(arg), &p);
4499 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4501 video_enc.codec_id = video_id;
4502 type = AV_OPT_FLAG_VIDEO_PARAM;
4505 audio_enc.codec_id = audio_id;
4506 type = AV_OPT_FLAG_AUDIO_PARAM;
4508 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4509 ERROR("AVPreset error: %s\n", arg);
4511 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4512 get_arg(arg, sizeof(arg), &p);
4513 if ((strlen(arg) == 4) && stream)
4514 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4515 } else if (!av_strcasecmp(cmd, "BitExact")) {
4517 video_enc.flags |= CODEC_FLAG_BITEXACT;
4518 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4520 video_enc.dct_algo = FF_DCT_FASTINT;
4521 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4523 video_enc.idct_algo = FF_IDCT_SIMPLE;
4524 } else if (!av_strcasecmp(cmd, "Qscale")) {
4525 get_arg(arg, sizeof(arg), &p);
4527 video_enc.flags |= CODEC_FLAG_QSCALE;
4528 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4530 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4531 get_arg(arg, sizeof(arg), &p);
4533 video_enc.max_qdiff = atoi(arg);
4534 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4535 ERROR("VideoQDiff out of range\n");
4538 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4539 get_arg(arg, sizeof(arg), &p);
4541 video_enc.qmax = atoi(arg);
4542 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4543 ERROR("VideoQMax out of range\n");
4546 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4547 get_arg(arg, sizeof(arg), &p);
4549 video_enc.qmin = atoi(arg);
4550 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4551 ERROR("VideoQMin out of range\n");
4554 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4555 get_arg(arg, sizeof(arg), &p);
4557 video_enc.lumi_masking = atof(arg);
4558 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4559 get_arg(arg, sizeof(arg), &p);
4561 video_enc.dark_masking = atof(arg);
4562 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4563 video_id = AV_CODEC_ID_NONE;
4564 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4565 audio_id = AV_CODEC_ID_NONE;
4566 } else if (!av_strcasecmp(cmd, "ACL")) {
4567 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4568 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4570 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4572 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4573 get_arg(arg, sizeof(arg), &p);
4575 av_freep(&stream->rtsp_option);
4576 stream->rtsp_option = av_strdup(arg);
4578 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4579 get_arg(arg, sizeof(arg), &p);
4581 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4582 ERROR("Invalid host/IP address: %s\n", arg);
4584 stream->is_multicast = 1;
4585 stream->loop = 1; /* default is looping */
4587 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4588 get_arg(arg, sizeof(arg), &p);
4590 stream->multicast_port = atoi(arg);
4591 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4592 get_arg(arg, sizeof(arg), &p);
4594 stream->multicast_ttl = atoi(arg);
4595 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4598 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4600 ERROR("No corresponding <Stream> for </Stream>\n");
4602 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4603 if (audio_id != AV_CODEC_ID_NONE) {
4604 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4605 audio_enc.codec_id = audio_id;
4606 add_codec(stream, &audio_enc);
4608 if (video_id != AV_CODEC_ID_NONE) {
4609 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4610 video_enc.codec_id = video_id;
4611 add_codec(stream, &video_enc);
4616 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4617 /*********************************************/
4619 if (stream || feed || redirect) {
4620 ERROR("Already in a tag\n");
4622 redirect = av_mallocz(sizeof(FFStream));
4624 ret = AVERROR(ENOMEM);
4627 *last_stream = redirect;
4628 last_stream = &redirect->next;
4630 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4631 q = strrchr(redirect->filename, '>');
4634 redirect->stream_type = STREAM_TYPE_REDIRECT;
4636 } else if (!av_strcasecmp(cmd, "URL")) {
4638 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4639 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4641 ERROR("No corresponding <Redirect> for </Redirect>\n");
4643 if (!redirect->feed_filename[0]) {
4644 ERROR("No URL found for <Redirect>\n");
4648 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4649 ERROR("Loadable modules no longer supported\n");
4651 ERROR("Incorrect keyword: '%s'\n", cmd);
4661 return AVERROR(EINVAL);
4666 static void handle_child_exit(int sig)
4671 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4674 for (feed = first_feed; feed; feed = feed->next) {
4675 if (feed->pid == pid) {
4676 int uptime = time(0) - feed->pid_start;
4679 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4682 /* Turn off any more restarts */
4683 feed->child_argv = 0;
4688 need_to_start_children = 1;
4691 static void opt_debug(void)
4694 logfilename[0] = '-';
4697 void show_help_default(const char *opt, const char *arg)
4699 printf("usage: ffserver [options]\n"
4700 "Hyper fast multi format Audio/Video streaming server\n");
4702 show_help_options(options, "Main options:", 0, 0, 0);
4705 static const OptionDef options[] = {
4706 #include "cmdutils_common_opts.h"
4707 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4708 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4709 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4713 int main(int argc, char **argv)
4715 struct sigaction sigact = { { 0 } };
4718 config_filename = av_strdup("/etc/ffserver.conf");
4720 parse_loglevel(argc, argv, options);
4722 avformat_network_init();
4724 show_banner(argc, argv, options);
4726 my_program_name = argv[0];
4728 parse_options(NULL, argc, argv, options, NULL);
4730 unsetenv("http_proxy"); /* Kill the http_proxy */
4732 av_lfg_init(&random_state, av_get_random_seed());
4734 sigact.sa_handler = handle_child_exit;
4735 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4736 sigaction(SIGCHLD, &sigact, 0);
4738 if ((ret = parse_ffconfig(config_filename)) < 0) {
4739 fprintf(stderr, "Error reading configuration file '%s': %s\n",
4740 config_filename, av_err2str(ret));
4743 av_freep(&config_filename);
4745 /* open log file if needed */
4746 if (logfilename[0] != '\0') {
4747 if (!strcmp(logfilename, "-"))
4750 logfile = fopen(logfilename, "a");
4751 av_log_set_callback(http_av_log);
4754 build_file_streams();
4756 build_feed_streams();
4758 compute_bandwidth();
4761 signal(SIGPIPE, SIG_IGN);
4763 if (http_server() < 0) {
4764 http_log("Could not start server\n");