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
32 #include "libavformat/avformat.h"
33 #include "libavformat/ffm.h"
34 #include "libavformat/network.h"
35 #include "libavformat/os_support.h"
36 #include "libavformat/rtpdec.h"
37 #include "libavformat/rtsp.h"
38 // XXX for ffio_open_dyn_packet_buffer, to be removed
39 #include "libavformat/avio_internal.h"
40 #include "libavutil/avstring.h"
41 #include "libavutil/lfg.h"
42 #include "libavutil/dict.h"
43 #include "libavutil/mathematics.h"
44 #include "libavutil/random_seed.h"
45 #include "libavutil/parseutils.h"
46 #include "libavutil/opt.h"
50 #include <sys/ioctl.h>
65 const char program_name[] = "ffserver";
66 const int program_birth_year = 2000;
68 static const OptionDef options[];
71 HTTPSTATE_WAIT_REQUEST,
72 HTTPSTATE_SEND_HEADER,
73 HTTPSTATE_SEND_DATA_HEADER,
74 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
75 HTTPSTATE_SEND_DATA_TRAILER,
76 HTTPSTATE_RECEIVE_DATA,
77 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
80 RTSPSTATE_WAIT_REQUEST,
82 RTSPSTATE_SEND_PACKET,
85 static const char *http_state[] = {
101 #define MAX_STREAMS 20
103 #define IOBUFFER_INIT_SIZE 8192
105 /* timeouts are in ms */
106 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
107 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
109 #define SYNC_TIMEOUT (10 * 1000)
111 typedef struct RTSPActionServerSetup {
113 char transport_option[512];
114 } RTSPActionServerSetup;
117 int64_t count1, count2;
118 int64_t time1, time2;
121 /* context associated with one connection */
122 typedef struct HTTPContext {
123 enum HTTPState state;
124 int fd; /* socket file descriptor */
125 struct sockaddr_in from_addr; /* origin */
126 struct pollfd *poll_entry; /* used when polling */
128 uint8_t *buffer_ptr, *buffer_end;
131 int chunked_encoding;
132 int chunk_size; /* 0 if it needs to be read */
133 struct HTTPContext *next;
134 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
138 /* input format handling */
139 AVFormatContext *fmt_in;
140 int64_t start_time; /* In milliseconds - this wraps fairly often */
141 int64_t first_pts; /* initial pts value */
142 int64_t cur_pts; /* current pts value from the stream in us */
143 int64_t cur_frame_duration; /* duration of the current frame in us */
144 int cur_frame_bytes; /* output frame size, needed to compute
145 the time at which we send each
147 int pts_stream_index; /* stream we choose as clock reference */
148 int64_t cur_clock; /* current clock reference value in us */
149 /* output format handling */
150 struct FFStream *stream;
151 /* -1 is invalid stream */
152 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
153 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
155 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
156 int last_packet_sent; /* true if last data packet was sent */
158 DataRateData datarate;
165 int is_packetized; /* if true, the stream is packetized */
166 int packet_stream_index; /* current stream for output in state machine */
168 /* RTSP state specific */
169 uint8_t *pb_buffer; /* XXX: use that in all the code */
171 int seq; /* RTSP sequence number */
173 /* RTP state specific */
174 enum RTSPLowerTransport rtp_protocol;
175 char session_id[32]; /* session id */
176 AVFormatContext *rtp_ctx[MAX_STREAMS];
178 /* RTP/UDP specific */
179 URLContext *rtp_handles[MAX_STREAMS];
181 /* RTP/TCP specific */
182 struct HTTPContext *rtsp_c;
183 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
186 /* each generated stream is described here */
190 STREAM_TYPE_REDIRECT,
193 enum IPAddressAction {
198 typedef struct IPAddressACL {
199 struct IPAddressACL *next;
200 enum IPAddressAction action;
201 /* These are in host order */
202 struct in_addr first;
206 /* description of each stream of the ffserver.conf file */
207 typedef struct FFStream {
208 enum StreamType stream_type;
209 char filename[1024]; /* stream filename */
210 struct FFStream *feed; /* feed we are using (can be null if
212 AVDictionary *in_opts; /* input parameters */
213 AVInputFormat *ifmt; /* if non NULL, force input format */
216 char dynamic_acl[1024];
218 int prebuffer; /* Number of millseconds early to start */
219 int64_t max_time; /* Number of milliseconds to run */
221 AVStream *streams[MAX_STREAMS];
222 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
223 char feed_filename[1024]; /* file name of the feed storage, or
224 input file name for a stream */
229 pid_t pid; /* Of ffmpeg process */
230 time_t pid_start; /* Of ffmpeg process */
232 struct FFStream *next;
233 unsigned bandwidth; /* bandwidth, in kbits/s */
236 /* multicast specific */
238 struct in_addr multicast_ip;
239 int multicast_port; /* first port used for multicast */
241 int loop; /* if true, send the stream in loops (only meaningful if file) */
244 int feed_opened; /* true if someone is writing to the feed */
245 int is_feed; /* true if it is a feed */
246 int readonly; /* True if writing is prohibited to the file */
247 int truncate; /* True if feeder connection truncate the feed file */
249 int64_t bytes_served;
250 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
251 int64_t feed_write_index; /* current write position in feed (it wraps around) */
252 int64_t feed_size; /* current size of feed */
253 struct FFStream *next_feed;
256 typedef struct FeedData {
257 long long data_count;
258 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
261 static struct sockaddr_in my_http_addr;
262 static struct sockaddr_in my_rtsp_addr;
264 static char logfilename[1024];
265 static HTTPContext *first_http_ctx;
266 static FFStream *first_feed; /* contains only feeds */
267 static FFStream *first_stream; /* contains all streams, including feeds */
269 static void new_connection(int server_fd, int is_rtsp);
270 static void close_connection(HTTPContext *c);
273 static int handle_connection(HTTPContext *c);
274 static int http_parse_request(HTTPContext *c);
275 static int http_send_data(HTTPContext *c);
276 static void compute_status(HTTPContext *c);
277 static int open_input_stream(HTTPContext *c, const char *info);
278 static int http_start_receive_data(HTTPContext *c);
279 static int http_receive_data(HTTPContext *c);
282 static int rtsp_parse_request(HTTPContext *c);
283 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
284 static void rtsp_cmd_options(HTTPContext *c, const char *url);
285 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
286 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
287 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
288 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
291 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
292 struct in_addr my_ip);
295 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
296 FFStream *stream, const char *session_id,
297 enum RTSPLowerTransport rtp_protocol);
298 static int rtp_new_av_stream(HTTPContext *c,
299 int stream_index, struct sockaddr_in *dest_addr,
300 HTTPContext *rtsp_c);
302 static const char *my_program_name;
303 static const char *my_program_dir;
305 static const char *config_filename = "/etc/ffserver.conf";
307 static int ffserver_debug;
308 static int ffserver_daemon;
309 static int no_launch;
310 static int need_to_start_children;
312 /* maximum number of simultaneous HTTP connections */
313 static unsigned int nb_max_http_connections = 2000;
314 static unsigned int nb_max_connections = 5;
315 static unsigned int nb_connections;
317 static uint64_t max_bandwidth = 1000;
318 static uint64_t current_bandwidth;
320 static int64_t cur_time; // Making this global saves on passing it around everywhere
322 static AVLFG random_state;
324 static FILE *logfile = NULL;
326 /* FIXME: make ffserver work with IPv6 */
327 void av_noreturn exit_program(int ret)
332 /* resolve host with also IP address parsing */
333 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
336 if (!ff_inet_aton(hostname, sin_addr)) {
338 struct addrinfo *ai, *cur;
339 struct addrinfo hints;
340 memset(&hints, 0, sizeof(hints));
341 hints.ai_family = AF_INET;
342 if (getaddrinfo(hostname, NULL, &hints, &ai))
344 /* getaddrinfo returns a linked list of addrinfo structs.
345 * Even if we set ai_family = AF_INET above, make sure
346 * that the returned one actually is of the correct type. */
347 for (cur = ai; cur; cur = cur->ai_next) {
348 if (cur->ai_family == AF_INET) {
349 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
358 hp = gethostbyname(hostname);
361 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
367 static char *ctime1(char *buf2)
375 p = buf2 + strlen(p) - 1;
381 static void http_vlog(const char *fmt, va_list vargs)
383 static int print_prefix = 1;
388 fprintf(logfile, "%s ", buf);
390 print_prefix = strstr(fmt, "\n") != NULL;
391 vfprintf(logfile, fmt, vargs);
397 __attribute__ ((format (printf, 1, 2)))
399 static void http_log(const char *fmt, ...)
402 va_start(vargs, fmt);
403 http_vlog(fmt, vargs);
407 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
409 static int print_prefix = 1;
410 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
411 if (level > av_log_get_level())
413 if (print_prefix && avc)
414 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
415 print_prefix = strstr(fmt, "\n") != NULL;
416 http_vlog(fmt, vargs);
419 static void log_connection(HTTPContext *c)
424 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
425 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
426 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
429 static void update_datarate(DataRateData *drd, int64_t count)
431 if (!drd->time1 && !drd->count1) {
432 drd->time1 = drd->time2 = cur_time;
433 drd->count1 = drd->count2 = count;
434 } else if (cur_time - drd->time2 > 5000) {
435 drd->time1 = drd->time2;
436 drd->count1 = drd->count2;
437 drd->time2 = cur_time;
442 /* In bytes per second */
443 static int compute_datarate(DataRateData *drd, int64_t count)
445 if (cur_time == drd->time1)
448 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
452 static void start_children(FFStream *feed)
457 for (; feed; feed = feed->next) {
458 if (feed->child_argv && !feed->pid) {
459 feed->pid_start = time(0);
464 http_log("Unable to create children\n");
473 av_strlcpy(pathname, my_program_name, sizeof(pathname));
475 slash = strrchr(pathname, '/');
480 strcpy(slash, "ffmpeg");
482 http_log("Launch command line: ");
483 http_log("%s ", pathname);
484 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
485 http_log("%s ", feed->child_argv[i]);
488 for (i = 3; i < 256; i++)
491 if (!ffserver_debug) {
492 i = open("/dev/null", O_RDWR);
501 /* This is needed to make relative pathnames work */
502 if (chdir(my_program_dir) < 0) {
503 http_log("chdir failed\n");
507 signal(SIGPIPE, SIG_DFL);
509 execvp(pathname, feed->child_argv);
517 /* open a listening socket */
518 static int socket_open_listen(struct sockaddr_in *my_addr)
522 server_fd = socket(AF_INET,SOCK_STREAM,0);
529 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
531 my_addr->sin_family = AF_INET;
532 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
534 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
536 closesocket(server_fd);
540 if (listen (server_fd, 5) < 0) {
542 closesocket(server_fd);
545 ff_socket_nonblock(server_fd, 1);
550 /* start all multicast streams */
551 static void start_multicast(void)
556 struct sockaddr_in dest_addr;
557 int default_port, stream_index;
560 for(stream = first_stream; stream != NULL; stream = stream->next) {
561 if (stream->is_multicast) {
562 /* open the RTP connection */
563 snprintf(session_id, sizeof(session_id), "%08x%08x",
564 av_lfg_get(&random_state), av_lfg_get(&random_state));
566 /* choose a port if none given */
567 if (stream->multicast_port == 0) {
568 stream->multicast_port = default_port;
572 dest_addr.sin_family = AF_INET;
573 dest_addr.sin_addr = stream->multicast_ip;
574 dest_addr.sin_port = htons(stream->multicast_port);
576 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
577 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
581 if (open_input_stream(rtp_c, "") < 0) {
582 http_log("Could not open input stream for stream '%s'\n",
587 /* open each RTP stream */
588 for(stream_index = 0; stream_index < stream->nb_streams;
590 dest_addr.sin_port = htons(stream->multicast_port +
592 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
593 http_log("Could not open output stream '%s/streamid=%d'\n",
594 stream->filename, stream_index);
599 /* change state to send data */
600 rtp_c->state = HTTPSTATE_SEND_DATA;
605 /* main loop of the http server */
606 static int http_server(void)
608 int server_fd = 0, rtsp_server_fd = 0;
609 int ret, delay, delay1;
610 struct pollfd *poll_table, *poll_entry;
611 HTTPContext *c, *c_next;
613 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
614 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
618 if (my_http_addr.sin_port) {
619 server_fd = socket_open_listen(&my_http_addr);
624 if (my_rtsp_addr.sin_port) {
625 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
626 if (rtsp_server_fd < 0)
630 if (!rtsp_server_fd && !server_fd) {
631 http_log("HTTP and RTSP disabled.\n");
635 http_log("FFserver started.\n");
637 start_children(first_feed);
642 poll_entry = poll_table;
644 poll_entry->fd = server_fd;
645 poll_entry->events = POLLIN;
648 if (rtsp_server_fd) {
649 poll_entry->fd = rtsp_server_fd;
650 poll_entry->events = POLLIN;
654 /* wait for events on each HTTP handle */
661 case HTTPSTATE_SEND_HEADER:
662 case RTSPSTATE_SEND_REPLY:
663 case RTSPSTATE_SEND_PACKET:
664 c->poll_entry = poll_entry;
666 poll_entry->events = POLLOUT;
669 case HTTPSTATE_SEND_DATA_HEADER:
670 case HTTPSTATE_SEND_DATA:
671 case HTTPSTATE_SEND_DATA_TRAILER:
672 if (!c->is_packetized) {
673 /* for TCP, we output as much as we can (may need to put a limit) */
674 c->poll_entry = poll_entry;
676 poll_entry->events = POLLOUT;
679 /* when ffserver is doing the timing, we work by
680 looking at which packet need to be sent every
682 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
687 case HTTPSTATE_WAIT_REQUEST:
688 case HTTPSTATE_RECEIVE_DATA:
689 case HTTPSTATE_WAIT_FEED:
690 case RTSPSTATE_WAIT_REQUEST:
691 /* need to catch errors */
692 c->poll_entry = poll_entry;
694 poll_entry->events = POLLIN;/* Maybe this will work */
698 c->poll_entry = NULL;
704 /* wait for an event on one connection. We poll at least every
705 second to handle timeouts */
707 ret = poll(poll_table, poll_entry - poll_table, delay);
708 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
709 ff_neterrno() != AVERROR(EINTR))
713 cur_time = av_gettime() / 1000;
715 if (need_to_start_children) {
716 need_to_start_children = 0;
717 start_children(first_feed);
720 /* now handle the events */
721 for(c = first_http_ctx; c != NULL; c = c_next) {
723 if (handle_connection(c) < 0) {
724 /* close and free the connection */
730 poll_entry = poll_table;
732 /* new HTTP connection request ? */
733 if (poll_entry->revents & POLLIN)
734 new_connection(server_fd, 0);
737 if (rtsp_server_fd) {
738 /* new RTSP connection request ? */
739 if (poll_entry->revents & POLLIN)
740 new_connection(rtsp_server_fd, 1);
745 /* start waiting for a new HTTP/RTSP request */
746 static void start_wait_request(HTTPContext *c, int is_rtsp)
748 c->buffer_ptr = c->buffer;
749 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
752 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
753 c->state = RTSPSTATE_WAIT_REQUEST;
755 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
756 c->state = HTTPSTATE_WAIT_REQUEST;
760 static void http_send_too_busy_reply(int fd)
763 int len = snprintf(buffer, sizeof(buffer),
764 "HTTP/1.0 503 Server too busy\r\n"
765 "Content-type: text/html\r\n"
767 "<html><head><title>Too busy</title></head><body>\r\n"
768 "<p>The server is too busy to serve your request at this time.</p>\r\n"
769 "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
770 "</body></html>\r\n",
771 nb_connections, nb_max_connections);
772 send(fd, buffer, len, 0);
776 static void new_connection(int server_fd, int is_rtsp)
778 struct sockaddr_in from_addr;
780 HTTPContext *c = NULL;
782 len = sizeof(from_addr);
783 fd = accept(server_fd, (struct sockaddr *)&from_addr,
786 http_log("error during accept %s\n", strerror(errno));
789 ff_socket_nonblock(fd, 1);
791 if (nb_connections >= nb_max_connections) {
792 http_send_too_busy_reply(fd);
796 /* add a new connection */
797 c = av_mallocz(sizeof(HTTPContext));
802 c->poll_entry = NULL;
803 c->from_addr = from_addr;
804 c->buffer_size = IOBUFFER_INIT_SIZE;
805 c->buffer = av_malloc(c->buffer_size);
809 c->next = first_http_ctx;
813 start_wait_request(c, is_rtsp);
825 static void close_connection(HTTPContext *c)
827 HTTPContext **cp, *c1;
829 AVFormatContext *ctx;
833 /* remove connection from list */
834 cp = &first_http_ctx;
835 while ((*cp) != NULL) {
843 /* remove references, if any (XXX: do it faster) */
844 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
849 /* remove connection associated resources */
853 /* close each frame parser */
854 for(i=0;i<c->fmt_in->nb_streams;i++) {
855 st = c->fmt_in->streams[i];
856 if (st->codec->codec)
857 avcodec_close(st->codec);
859 avformat_close_input(&c->fmt_in);
862 /* free RTP output streams if any */
865 nb_streams = c->stream->nb_streams;
867 for(i=0;i<nb_streams;i++) {
870 av_write_trailer(ctx);
871 av_dict_free(&ctx->metadata);
872 av_free(ctx->streams[0]);
875 h = c->rtp_handles[i];
882 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
885 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
886 av_write_trailer(ctx);
887 av_freep(&c->pb_buffer);
888 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
893 for(i=0; i<ctx->nb_streams; i++)
894 av_free(ctx->streams[i]);
896 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
897 current_bandwidth -= c->stream->bandwidth;
899 /* signal that there is no feed if we are the feeder socket */
900 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
901 c->stream->feed_opened = 0;
905 av_freep(&c->pb_buffer);
906 av_freep(&c->packet_buffer);
912 static int handle_connection(HTTPContext *c)
917 case HTTPSTATE_WAIT_REQUEST:
918 case RTSPSTATE_WAIT_REQUEST:
920 if ((c->timeout - cur_time) < 0)
922 if (c->poll_entry->revents & (POLLERR | POLLHUP))
925 /* no need to read if no events */
926 if (!(c->poll_entry->revents & POLLIN))
930 len = recv(c->fd, c->buffer_ptr, 1, 0);
932 if (ff_neterrno() != AVERROR(EAGAIN) &&
933 ff_neterrno() != AVERROR(EINTR))
935 } else if (len == 0) {
938 /* search for end of request. */
940 c->buffer_ptr += len;
942 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
943 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
944 /* request found : parse it and reply */
945 if (c->state == HTTPSTATE_WAIT_REQUEST) {
946 ret = http_parse_request(c);
948 ret = rtsp_parse_request(c);
952 } else if (ptr >= c->buffer_end) {
953 /* request too long: cannot do anything */
955 } else goto read_loop;
959 case HTTPSTATE_SEND_HEADER:
960 if (c->poll_entry->revents & (POLLERR | POLLHUP))
963 /* no need to write if no events */
964 if (!(c->poll_entry->revents & POLLOUT))
966 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
968 if (ff_neterrno() != AVERROR(EAGAIN) &&
969 ff_neterrno() != AVERROR(EINTR)) {
970 /* error : close connection */
971 av_freep(&c->pb_buffer);
975 c->buffer_ptr += len;
977 c->stream->bytes_served += len;
978 c->data_count += len;
979 if (c->buffer_ptr >= c->buffer_end) {
980 av_freep(&c->pb_buffer);
984 /* all the buffer was sent : synchronize to the incoming stream */
985 c->state = HTTPSTATE_SEND_DATA_HEADER;
986 c->buffer_ptr = c->buffer_end = c->buffer;
991 case HTTPSTATE_SEND_DATA:
992 case HTTPSTATE_SEND_DATA_HEADER:
993 case HTTPSTATE_SEND_DATA_TRAILER:
994 /* for packetized output, we consider we can always write (the
995 input streams sets the speed). It may be better to verify
996 that we do not rely too much on the kernel queues */
997 if (!c->is_packetized) {
998 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1001 /* no need to read if no events */
1002 if (!(c->poll_entry->revents & POLLOUT))
1005 if (http_send_data(c) < 0)
1007 /* close connection if trailer sent */
1008 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1011 case HTTPSTATE_RECEIVE_DATA:
1012 /* no need to read if no events */
1013 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1015 if (!(c->poll_entry->revents & POLLIN))
1017 if (http_receive_data(c) < 0)
1020 case HTTPSTATE_WAIT_FEED:
1021 /* no need to read if no events */
1022 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1025 /* nothing to do, we'll be waken up by incoming feed packets */
1028 case RTSPSTATE_SEND_REPLY:
1029 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1030 av_freep(&c->pb_buffer);
1033 /* no need to write if no events */
1034 if (!(c->poll_entry->revents & POLLOUT))
1036 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1038 if (ff_neterrno() != AVERROR(EAGAIN) &&
1039 ff_neterrno() != AVERROR(EINTR)) {
1040 /* error : close connection */
1041 av_freep(&c->pb_buffer);
1045 c->buffer_ptr += len;
1046 c->data_count += len;
1047 if (c->buffer_ptr >= c->buffer_end) {
1048 /* all the buffer was sent : wait for a new request */
1049 av_freep(&c->pb_buffer);
1050 start_wait_request(c, 1);
1054 case RTSPSTATE_SEND_PACKET:
1055 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1056 av_freep(&c->packet_buffer);
1059 /* no need to write if no events */
1060 if (!(c->poll_entry->revents & POLLOUT))
1062 len = send(c->fd, c->packet_buffer_ptr,
1063 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1065 if (ff_neterrno() != AVERROR(EAGAIN) &&
1066 ff_neterrno() != AVERROR(EINTR)) {
1067 /* error : close connection */
1068 av_freep(&c->packet_buffer);
1072 c->packet_buffer_ptr += len;
1073 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1074 /* all the buffer was sent : wait for a new request */
1075 av_freep(&c->packet_buffer);
1076 c->state = RTSPSTATE_WAIT_REQUEST;
1080 case HTTPSTATE_READY:
1089 static int extract_rates(char *rates, int ratelen, const char *request)
1093 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1094 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1095 const char *q = p + 7;
1097 while (*q && *q != '\n' && isspace(*q))
1100 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1106 memset(rates, 0xff, ratelen);
1109 while (*q && *q != '\n' && *q != ':')
1112 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1116 if (stream_no < ratelen && stream_no >= 0)
1117 rates[stream_no] = rate_no;
1119 while (*q && *q != '\n' && !isspace(*q))
1126 p = strchr(p, '\n');
1136 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1139 int best_bitrate = 100000000;
1142 for (i = 0; i < feed->nb_streams; i++) {
1143 AVCodecContext *feed_codec = feed->streams[i]->codec;
1145 if (feed_codec->codec_id != codec->codec_id ||
1146 feed_codec->sample_rate != codec->sample_rate ||
1147 feed_codec->width != codec->width ||
1148 feed_codec->height != codec->height)
1151 /* Potential stream */
1153 /* We want the fastest stream less than bit_rate, or the slowest
1154 * faster than bit_rate
1157 if (feed_codec->bit_rate <= bit_rate) {
1158 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1159 best_bitrate = feed_codec->bit_rate;
1163 if (feed_codec->bit_rate < best_bitrate) {
1164 best_bitrate = feed_codec->bit_rate;
1173 static int modify_current_stream(HTTPContext *c, char *rates)
1176 FFStream *req = c->stream;
1177 int action_required = 0;
1179 /* Not much we can do for a feed */
1183 for (i = 0; i < req->nb_streams; i++) {
1184 AVCodecContext *codec = req->streams[i]->codec;
1188 c->switch_feed_streams[i] = req->feed_streams[i];
1191 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1194 /* Wants off or slow */
1195 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1197 /* This doesn't work well when it turns off the only stream! */
1198 c->switch_feed_streams[i] = -2;
1199 c->feed_streams[i] = -2;
1204 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1205 action_required = 1;
1208 return action_required;
1211 /* XXX: factorize in utils.c ? */
1212 /* XXX: take care with different space meaning */
1213 static void skip_spaces(const char **pp)
1217 while (*p == ' ' || *p == '\t')
1222 static void get_word(char *buf, int buf_size, const char **pp)
1230 while (!isspace(*p) && *p != '\0') {
1231 if ((q - buf) < buf_size - 1)
1240 static void get_arg(char *buf, int buf_size, const char **pp)
1247 while (isspace(*p)) p++;
1250 if (*p == '\"' || *p == '\'')
1262 if ((q - buf) < buf_size - 1)
1267 if (quote && *p == quote)
1272 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1273 const char *p, const char *filename, int line_num)
1279 get_arg(arg, sizeof(arg), &p);
1280 if (av_strcasecmp(arg, "allow") == 0)
1281 acl.action = IP_ALLOW;
1282 else if (av_strcasecmp(arg, "deny") == 0)
1283 acl.action = IP_DENY;
1285 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1286 filename, line_num, arg);
1290 get_arg(arg, sizeof(arg), &p);
1292 if (resolve_host(&acl.first, arg) != 0) {
1293 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1294 filename, line_num, arg);
1297 acl.last = acl.first;
1299 get_arg(arg, sizeof(arg), &p);
1302 if (resolve_host(&acl.last, arg) != 0) {
1303 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1304 filename, line_num, arg);
1310 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1311 IPAddressACL **naclp = 0;
1317 naclp = &stream->acl;
1323 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1324 filename, line_num);
1330 naclp = &(*naclp)->next;
1338 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1343 IPAddressACL *acl = NULL;
1347 f = fopen(stream->dynamic_acl, "r");
1349 perror(stream->dynamic_acl);
1353 acl = av_mallocz(sizeof(IPAddressACL));
1357 if (fgets(line, sizeof(line), f) == NULL)
1363 if (*p == '\0' || *p == '#')
1365 get_arg(cmd, sizeof(cmd), &p);
1367 if (!av_strcasecmp(cmd, "ACL"))
1368 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1375 static void free_acl_list(IPAddressACL *in_acl)
1377 IPAddressACL *pacl,*pacl2;
1387 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1389 enum IPAddressAction last_action = IP_DENY;
1391 struct in_addr *src = &c->from_addr.sin_addr;
1392 unsigned long src_addr = src->s_addr;
1394 for (acl = in_acl; acl; acl = acl->next) {
1395 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1396 return (acl->action == IP_ALLOW) ? 1 : 0;
1397 last_action = acl->action;
1400 /* Nothing matched, so return not the last action */
1401 return (last_action == IP_DENY) ? 1 : 0;
1404 static int validate_acl(FFStream *stream, HTTPContext *c)
1410 /* if stream->acl is null validate_acl_list will return 1 */
1411 ret = validate_acl_list(stream->acl, c);
1413 if (stream->dynamic_acl[0]) {
1414 acl = parse_dynamic_acl(stream, c);
1416 ret = validate_acl_list(acl, c);
1424 /* compute the real filename of a file by matching it without its
1425 extensions to all the stream filenames */
1426 static void compute_real_filename(char *filename, int max_size)
1433 /* compute filename by matching without the file extensions */
1434 av_strlcpy(file1, filename, sizeof(file1));
1435 p = strrchr(file1, '.');
1438 for(stream = first_stream; stream != NULL; stream = stream->next) {
1439 av_strlcpy(file2, stream->filename, sizeof(file2));
1440 p = strrchr(file2, '.');
1443 if (!strcmp(file1, file2)) {
1444 av_strlcpy(filename, stream->filename, max_size);
1459 /* parse http request and prepare header */
1460 static int http_parse_request(HTTPContext *c)
1463 enum RedirType redir_type;
1465 char info[1024], filename[1024];
1469 const char *mime_type;
1473 char *useragent = 0;
1476 get_word(cmd, sizeof(cmd), (const char **)&p);
1477 av_strlcpy(c->method, cmd, sizeof(c->method));
1479 if (!strcmp(cmd, "GET"))
1481 else if (!strcmp(cmd, "POST"))
1486 get_word(url, sizeof(url), (const char **)&p);
1487 av_strlcpy(c->url, url, sizeof(c->url));
1489 get_word(protocol, sizeof(protocol), (const char **)&p);
1490 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1493 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1496 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1498 /* find the filename and the optional info string in the request */
1499 p = strchr(url, '?');
1501 av_strlcpy(info, p, sizeof(info));
1506 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1508 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1509 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1511 if (*useragent && *useragent != '\n' && isspace(*useragent))
1515 p = strchr(p, '\n');
1522 redir_type = REDIR_NONE;
1523 if (av_match_ext(filename, "asx")) {
1524 redir_type = REDIR_ASX;
1525 filename[strlen(filename)-1] = 'f';
1526 } else if (av_match_ext(filename, "asf") &&
1527 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1528 /* if this isn't WMP or lookalike, return the redirector file */
1529 redir_type = REDIR_ASF;
1530 } else if (av_match_ext(filename, "rpm,ram")) {
1531 redir_type = REDIR_RAM;
1532 strcpy(filename + strlen(filename)-2, "m");
1533 } else if (av_match_ext(filename, "rtsp")) {
1534 redir_type = REDIR_RTSP;
1535 compute_real_filename(filename, sizeof(filename) - 1);
1536 } else if (av_match_ext(filename, "sdp")) {
1537 redir_type = REDIR_SDP;
1538 compute_real_filename(filename, sizeof(filename) - 1);
1541 // "redirect" / request to index.html
1542 if (!strlen(filename))
1543 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1545 stream = first_stream;
1546 while (stream != NULL) {
1547 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1549 stream = stream->next;
1551 if (stream == NULL) {
1552 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1553 http_log("File '%s' not found\n", url);
1558 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1559 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1561 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1562 c->http_error = 301;
1564 q += snprintf(q, c->buffer_size,
1565 "HTTP/1.0 301 Moved\r\n"
1567 "Content-type: text/html\r\n"
1569 "<html><head><title>Moved</title></head><body>\r\n"
1570 "You should be <a href=\"%s\">redirected</a>.\r\n"
1571 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1572 /* prepare output buffer */
1573 c->buffer_ptr = c->buffer;
1575 c->state = HTTPSTATE_SEND_HEADER;
1579 /* If this is WMP, get the rate information */
1580 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1581 if (modify_current_stream(c, ratebuf)) {
1582 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1583 if (c->switch_feed_streams[i] >= 0)
1584 c->switch_feed_streams[i] = -1;
1589 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1590 current_bandwidth += stream->bandwidth;
1592 /* If already streaming this feed, do not let start another feeder. */
1593 if (stream->feed_opened) {
1594 snprintf(msg, sizeof(msg), "This feed is already being received.");
1595 http_log("Feed '%s' already being received\n", stream->feed_filename);
1599 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1600 c->http_error = 503;
1602 q += snprintf(q, c->buffer_size,
1603 "HTTP/1.0 503 Server too busy\r\n"
1604 "Content-type: text/html\r\n"
1606 "<html><head><title>Too busy</title></head><body>\r\n"
1607 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1608 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1609 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1610 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1611 /* prepare output buffer */
1612 c->buffer_ptr = c->buffer;
1614 c->state = HTTPSTATE_SEND_HEADER;
1618 if (redir_type != REDIR_NONE) {
1621 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1622 if (av_strncasecmp(p, "Host:", 5) == 0) {
1626 p = strchr(p, '\n');
1637 while (isspace(*hostinfo))
1640 eoh = strchr(hostinfo, '\n');
1642 if (eoh[-1] == '\r')
1645 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1646 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1647 hostbuf[eoh - hostinfo] = 0;
1649 c->http_error = 200;
1651 switch(redir_type) {
1653 q += snprintf(q, c->buffer_size,
1654 "HTTP/1.0 200 ASX Follows\r\n"
1655 "Content-type: video/x-ms-asf\r\n"
1657 "<ASX Version=\"3\">\r\n"
1658 //"<!-- Autogenerated by ffserver -->\r\n"
1659 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1660 "</ASX>\r\n", hostbuf, filename, info);
1663 q += snprintf(q, c->buffer_size,
1664 "HTTP/1.0 200 RAM Follows\r\n"
1665 "Content-type: audio/x-pn-realaudio\r\n"
1667 "# Autogenerated by ffserver\r\n"
1668 "http://%s/%s%s\r\n", hostbuf, filename, info);
1671 q += snprintf(q, c->buffer_size,
1672 "HTTP/1.0 200 ASF Redirect follows\r\n"
1673 "Content-type: video/x-ms-asf\r\n"
1676 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1680 char hostname[256], *p;
1681 /* extract only hostname */
1682 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1683 p = strrchr(hostname, ':');
1686 q += snprintf(q, c->buffer_size,
1687 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1688 /* XXX: incorrect mime type ? */
1689 "Content-type: application/x-rtsp\r\n"
1691 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1697 int sdp_data_size, len;
1698 struct sockaddr_in my_addr;
1700 q += snprintf(q, c->buffer_size,
1701 "HTTP/1.0 200 OK\r\n"
1702 "Content-type: application/sdp\r\n"
1705 len = sizeof(my_addr);
1706 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1708 /* XXX: should use a dynamic buffer */
1709 sdp_data_size = prepare_sdp_description(stream,
1712 if (sdp_data_size > 0) {
1713 memcpy(q, sdp_data, sdp_data_size);
1725 /* prepare output buffer */
1726 c->buffer_ptr = c->buffer;
1728 c->state = HTTPSTATE_SEND_HEADER;
1734 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1738 stream->conns_served++;
1740 /* XXX: add there authenticate and IP match */
1743 /* if post, it means a feed is being sent */
1744 if (!stream->is_feed) {
1745 /* However it might be a status report from WMP! Let us log the
1746 * data as it might come in handy one day. */
1750 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1751 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1755 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1756 client_id = strtol(p + 18, 0, 10);
1757 p = strchr(p, '\n');
1765 char *eol = strchr(logline, '\n');
1770 if (eol[-1] == '\r')
1772 http_log("%.*s\n", (int) (eol - logline), logline);
1773 c->suppress_log = 1;
1778 http_log("\nGot request:\n%s\n", c->buffer);
1781 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1784 /* Now we have to find the client_id */
1785 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1786 if (wmpc->wmp_client_id == client_id)
1790 if (wmpc && modify_current_stream(wmpc, ratebuf))
1791 wmpc->switch_pending = 1;
1794 snprintf(msg, sizeof(msg), "POST command not handled");
1798 if (http_start_receive_data(c) < 0) {
1799 snprintf(msg, sizeof(msg), "could not open feed");
1803 c->state = HTTPSTATE_RECEIVE_DATA;
1808 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1809 http_log("\nGot request:\n%s\n", c->buffer);
1812 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1815 /* open input stream */
1816 if (open_input_stream(c, info) < 0) {
1817 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1821 /* prepare http header */
1823 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1824 mime_type = c->stream->fmt->mime_type;
1826 mime_type = "application/x-octet-stream";
1827 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1829 /* for asf, we need extra headers */
1830 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1831 /* Need to allocate a client id */
1833 c->wmp_client_id = av_lfg_get(&random_state);
1835 q += snprintf(q, q - (char *) 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);
1837 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1838 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1840 /* prepare output buffer */
1842 c->buffer_ptr = c->buffer;
1844 c->state = HTTPSTATE_SEND_HEADER;
1847 c->http_error = 404;
1849 q += snprintf(q, c->buffer_size,
1850 "HTTP/1.0 404 Not Found\r\n"
1851 "Content-type: text/html\r\n"
1854 "<head><title>404 Not Found</title></head>\n"
1857 /* prepare output buffer */
1858 c->buffer_ptr = c->buffer;
1860 c->state = HTTPSTATE_SEND_HEADER;
1864 c->http_error = 200; /* horrible : we use this value to avoid
1865 going to the send data state */
1866 c->state = HTTPSTATE_SEND_HEADER;
1870 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1872 static const char *suffix = " kMGTP";
1875 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1877 avio_printf(pb, "%"PRId64"%c", count, *s);
1880 static void compute_status(HTTPContext *c)
1889 if (avio_open_dyn_buf(&pb) < 0) {
1890 /* XXX: return an error ? */
1891 c->buffer_ptr = c->buffer;
1892 c->buffer_end = c->buffer;
1896 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1897 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1898 avio_printf(pb, "Pragma: no-cache\r\n");
1899 avio_printf(pb, "\r\n");
1901 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1902 if (c->stream->feed_filename[0])
1903 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1904 avio_printf(pb, "</head>\n<body>");
1905 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1907 avio_printf(pb, "<h2>Available Streams</h2>\n");
1908 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1909 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");
1910 stream = first_stream;
1911 while (stream != NULL) {
1912 char sfilename[1024];
1915 if (stream->feed != stream) {
1916 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1917 eosf = sfilename + strlen(sfilename);
1918 if (eosf - sfilename >= 4) {
1919 if (strcmp(eosf - 4, ".asf") == 0)
1920 strcpy(eosf - 4, ".asx");
1921 else if (strcmp(eosf - 3, ".rm") == 0)
1922 strcpy(eosf - 3, ".ram");
1923 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1924 /* generate a sample RTSP director if
1925 unicast. Generate an SDP redirector if
1927 eosf = strrchr(sfilename, '.');
1929 eosf = sfilename + strlen(sfilename);
1930 if (stream->is_multicast)
1931 strcpy(eosf, ".sdp");
1933 strcpy(eosf, ".rtsp");
1937 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1938 sfilename, stream->filename);
1939 avio_printf(pb, "<td align=right> %d <td align=right> ",
1940 stream->conns_served);
1941 fmt_bytecount(pb, stream->bytes_served);
1942 switch(stream->stream_type) {
1943 case STREAM_TYPE_LIVE: {
1944 int audio_bit_rate = 0;
1945 int video_bit_rate = 0;
1946 const char *audio_codec_name = "";
1947 const char *video_codec_name = "";
1948 const char *audio_codec_name_extra = "";
1949 const char *video_codec_name_extra = "";
1951 for(i=0;i<stream->nb_streams;i++) {
1952 AVStream *st = stream->streams[i];
1953 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1954 switch(st->codec->codec_type) {
1955 case AVMEDIA_TYPE_AUDIO:
1956 audio_bit_rate += st->codec->bit_rate;
1958 if (*audio_codec_name)
1959 audio_codec_name_extra = "...";
1960 audio_codec_name = codec->name;
1963 case AVMEDIA_TYPE_VIDEO:
1964 video_bit_rate += st->codec->bit_rate;
1966 if (*video_codec_name)
1967 video_codec_name_extra = "...";
1968 video_codec_name = codec->name;
1971 case AVMEDIA_TYPE_DATA:
1972 video_bit_rate += st->codec->bit_rate;
1978 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",
1981 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1982 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1984 avio_printf(pb, "<td>%s", stream->feed->filename);
1986 avio_printf(pb, "<td>%s", stream->feed_filename);
1987 avio_printf(pb, "\n");
1991 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1995 stream = stream->next;
1997 avio_printf(pb, "</table>\n");
1999 stream = first_stream;
2000 while (stream != NULL) {
2001 if (stream->feed == stream) {
2002 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2004 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2006 #if defined(linux) && !defined(CONFIG_NOCUTILS)
2011 /* This is somewhat linux specific I guess */
2012 snprintf(ps_cmd, sizeof(ps_cmd),
2013 "ps -o \"%%cpu,cputime\" --no-headers %d",
2016 pid_stat = popen(ps_cmd, "r");
2021 if (fscanf(pid_stat, "%10s %64s", cpuperc,
2023 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2031 avio_printf(pb, "<p>");
2033 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");
2035 for (i = 0; i < stream->nb_streams; i++) {
2036 AVStream *st = stream->streams[i];
2037 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2038 const char *type = "unknown";
2039 char parameters[64];
2043 switch(st->codec->codec_type) {
2044 case AVMEDIA_TYPE_AUDIO:
2046 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2048 case AVMEDIA_TYPE_VIDEO:
2050 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2051 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2056 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2057 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2059 avio_printf(pb, "</table>\n");
2062 stream = stream->next;
2065 /* connection status */
2066 avio_printf(pb, "<h2>Connection Status</h2>\n");
2068 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2069 nb_connections, nb_max_connections);
2071 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2072 current_bandwidth, max_bandwidth);
2074 avio_printf(pb, "<table>\n");
2075 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");
2076 c1 = first_http_ctx;
2078 while (c1 != NULL) {
2084 for (j = 0; j < c1->stream->nb_streams; j++) {
2085 if (!c1->stream->feed)
2086 bitrate += c1->stream->streams[j]->codec->bit_rate;
2087 else if (c1->feed_streams[j] >= 0)
2088 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2093 p = inet_ntoa(c1->from_addr.sin_addr);
2094 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2096 c1->stream ? c1->stream->filename : "",
2097 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2100 http_state[c1->state]);
2101 fmt_bytecount(pb, bitrate);
2102 avio_printf(pb, "<td align=right>");
2103 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2104 avio_printf(pb, "<td align=right>");
2105 fmt_bytecount(pb, c1->data_count);
2106 avio_printf(pb, "\n");
2109 avio_printf(pb, "</table>\n");
2114 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2115 avio_printf(pb, "</body>\n</html>\n");
2117 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2118 c->buffer_ptr = c->pb_buffer;
2119 c->buffer_end = c->pb_buffer + len;
2122 /* check if the parser needs to be opened for stream i */
2123 static void open_parser(AVFormatContext *s, int i)
2125 AVStream *st = s->streams[i];
2128 if (!st->codec->codec) {
2129 codec = avcodec_find_decoder(st->codec->codec_id);
2130 if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2131 st->codec->parse_only = 1;
2132 if (avcodec_open2(st->codec, codec, NULL) < 0)
2133 st->codec->parse_only = 0;
2138 static int open_input_stream(HTTPContext *c, const char *info)
2141 char input_filename[1024];
2142 AVFormatContext *s = NULL;
2146 /* find file name */
2147 if (c->stream->feed) {
2148 strcpy(input_filename, c->stream->feed->feed_filename);
2149 /* compute position (absolute time) */
2150 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2151 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2153 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2154 int prebuffer = strtol(buf, 0, 10);
2155 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2157 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2159 strcpy(input_filename, c->stream->feed_filename);
2160 /* compute position (relative time) */
2161 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2162 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2167 if (input_filename[0] == '\0')
2171 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2172 http_log("could not open %s: %d\n", input_filename, ret);
2175 s->flags |= AVFMT_FLAG_GENPTS;
2177 if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
2178 http_log("Could not find stream info '%s'\n", input_filename);
2179 avformat_close_input(&s);
2183 /* open each parser */
2184 for(i=0;i<s->nb_streams;i++)
2187 /* choose stream as clock source (we favorize video stream if
2188 present) for packet sending */
2189 c->pts_stream_index = 0;
2190 for(i=0;i<c->stream->nb_streams;i++) {
2191 if (c->pts_stream_index == 0 &&
2192 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2193 c->pts_stream_index = i;
2197 if (c->fmt_in->iformat->read_seek)
2198 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2199 /* set the start time (needed for maxtime and RTP packet timing) */
2200 c->start_time = cur_time;
2201 c->first_pts = AV_NOPTS_VALUE;
2205 /* return the server clock (in us) */
2206 static int64_t get_server_clock(HTTPContext *c)
2208 /* compute current pts value from system time */
2209 return (cur_time - c->start_time) * 1000;
2212 /* return the estimated time at which the current packet must be sent
2214 static int64_t get_packet_send_clock(HTTPContext *c)
2216 int bytes_left, bytes_sent, frame_bytes;
2218 frame_bytes = c->cur_frame_bytes;
2219 if (frame_bytes <= 0)
2222 bytes_left = c->buffer_end - c->buffer_ptr;
2223 bytes_sent = frame_bytes - bytes_left;
2224 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2229 static int http_prepare_data(HTTPContext *c)
2232 AVFormatContext *ctx;
2234 av_freep(&c->pb_buffer);
2236 case HTTPSTATE_SEND_DATA_HEADER:
2237 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2238 av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2239 av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2240 av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2241 av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2243 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2245 for(i=0;i<c->stream->nb_streams;i++) {
2247 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2248 /* if file or feed, then just take streams from FFStream struct */
2249 if (!c->stream->feed ||
2250 c->stream->feed == c->stream)
2251 src = c->stream->streams[i];
2253 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2255 *(c->fmt_ctx.streams[i]) = *src;
2256 c->fmt_ctx.streams[i]->priv_data = 0;
2257 c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2258 AVStream, not in codec */
2260 /* set output format parameters */
2261 c->fmt_ctx.oformat = c->stream->fmt;
2262 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2264 c->got_key_frame = 0;
2266 /* prepare header and save header data in a stream */
2267 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2268 /* XXX: potential leak */
2271 c->fmt_ctx.pb->seekable = 0;
2274 * HACK to avoid mpeg ps muxer to spit many underflow errors
2275 * Default value from FFmpeg
2276 * Try to set it use configuration option
2278 c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
2279 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2281 if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2282 http_log("Error writing output header\n");
2285 av_dict_free(&c->fmt_ctx.metadata);
2287 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2288 c->buffer_ptr = c->pb_buffer;
2289 c->buffer_end = c->pb_buffer + len;
2291 c->state = HTTPSTATE_SEND_DATA;
2292 c->last_packet_sent = 0;
2294 case HTTPSTATE_SEND_DATA:
2295 /* find a new packet */
2296 /* read a packet from the input stream */
2297 if (c->stream->feed)
2298 ffm_set_write_index(c->fmt_in,
2299 c->stream->feed->feed_write_index,
2300 c->stream->feed->feed_size);
2302 if (c->stream->max_time &&
2303 c->stream->max_time + c->start_time - cur_time < 0)
2304 /* We have timed out */
2305 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2309 ret = av_read_frame(c->fmt_in, &pkt);
2311 if (c->stream->feed) {
2312 /* if coming from feed, it means we reached the end of the
2313 ffm file, so must wait for more data */
2314 c->state = HTTPSTATE_WAIT_FEED;
2315 return 1; /* state changed */
2316 } else if (ret == AVERROR(EAGAIN)) {
2317 /* input not ready, come back later */
2320 if (c->stream->loop) {
2321 avformat_close_input(&c->fmt_in);
2322 if (open_input_stream(c, "") < 0)
2327 /* must send trailer now because eof or error */
2328 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2332 int source_index = pkt.stream_index;
2333 /* update first pts if needed */
2334 if (c->first_pts == AV_NOPTS_VALUE) {
2335 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2336 c->start_time = cur_time;
2338 /* send it to the appropriate stream */
2339 if (c->stream->feed) {
2340 /* if coming from a feed, select the right stream */
2341 if (c->switch_pending) {
2342 c->switch_pending = 0;
2343 for(i=0;i<c->stream->nb_streams;i++) {
2344 if (c->switch_feed_streams[i] == pkt.stream_index)
2345 if (pkt.flags & AV_PKT_FLAG_KEY)
2346 c->switch_feed_streams[i] = -1;
2347 if (c->switch_feed_streams[i] >= 0)
2348 c->switch_pending = 1;
2351 for(i=0;i<c->stream->nb_streams;i++) {
2352 if (c->stream->feed_streams[i] == pkt.stream_index) {
2353 AVStream *st = c->fmt_in->streams[source_index];
2354 pkt.stream_index = i;
2355 if (pkt.flags & AV_PKT_FLAG_KEY &&
2356 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2357 c->stream->nb_streams == 1))
2358 c->got_key_frame = 1;
2359 if (!c->stream->send_on_key || c->got_key_frame)
2364 AVCodecContext *codec;
2365 AVStream *ist, *ost;
2367 ist = c->fmt_in->streams[source_index];
2368 /* specific handling for RTP: we use several
2369 output stream (one for each RTP
2370 connection). XXX: need more abstract handling */
2371 if (c->is_packetized) {
2372 /* compute send time and duration */
2373 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2374 c->cur_pts -= c->first_pts;
2375 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2376 /* find RTP context */
2377 c->packet_stream_index = pkt.stream_index;
2378 ctx = c->rtp_ctx[c->packet_stream_index];
2380 av_free_packet(&pkt);
2383 codec = ctx->streams[0]->codec;
2384 /* only one stream per RTP connection */
2385 pkt.stream_index = 0;
2389 codec = ctx->streams[pkt.stream_index]->codec;
2392 if (c->is_packetized) {
2393 int max_packet_size;
2394 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2395 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2397 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2398 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2400 ret = avio_open_dyn_buf(&ctx->pb);
2403 /* XXX: potential leak */
2406 ost = ctx->streams[pkt.stream_index];
2408 ctx->pb->seekable = 0;
2409 if (pkt.dts != AV_NOPTS_VALUE)
2410 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2411 if (pkt.pts != AV_NOPTS_VALUE)
2412 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2413 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2414 if (av_write_frame(ctx, &pkt) < 0) {
2415 http_log("Error writing frame to output\n");
2416 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2419 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2420 c->cur_frame_bytes = len;
2421 c->buffer_ptr = c->pb_buffer;
2422 c->buffer_end = c->pb_buffer + len;
2424 codec->frame_number++;
2426 av_free_packet(&pkt);
2430 av_free_packet(&pkt);
2435 case HTTPSTATE_SEND_DATA_TRAILER:
2436 /* last packet test ? */
2437 if (c->last_packet_sent || c->is_packetized)
2440 /* prepare header */
2441 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2442 /* XXX: potential leak */
2445 c->fmt_ctx.pb->seekable = 0;
2446 av_write_trailer(ctx);
2447 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2448 c->buffer_ptr = c->pb_buffer;
2449 c->buffer_end = c->pb_buffer + len;
2451 c->last_packet_sent = 1;
2457 /* should convert the format at the same time */
2458 /* send data starting at c->buffer_ptr to the output connection
2459 (either UDP or TCP connection) */
2460 static int http_send_data(HTTPContext *c)
2465 if (c->buffer_ptr >= c->buffer_end) {
2466 ret = http_prepare_data(c);
2470 /* state change requested */
2473 if (c->is_packetized) {
2474 /* RTP data output */
2475 len = c->buffer_end - c->buffer_ptr;
2477 /* fail safe - should never happen */
2479 c->buffer_ptr = c->buffer_end;
2482 len = (c->buffer_ptr[0] << 24) |
2483 (c->buffer_ptr[1] << 16) |
2484 (c->buffer_ptr[2] << 8) |
2486 if (len > (c->buffer_end - c->buffer_ptr))
2488 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2489 /* nothing to send yet: we can wait */
2493 c->data_count += len;
2494 update_datarate(&c->datarate, c->data_count);
2496 c->stream->bytes_served += len;
2498 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2499 /* RTP packets are sent inside the RTSP TCP connection */
2501 int interleaved_index, size;
2503 HTTPContext *rtsp_c;
2506 /* if no RTSP connection left, error */
2509 /* if already sending something, then wait. */
2510 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2512 if (avio_open_dyn_buf(&pb) < 0)
2514 interleaved_index = c->packet_stream_index * 2;
2515 /* RTCP packets are sent at odd indexes */
2516 if (c->buffer_ptr[1] == 200)
2517 interleaved_index++;
2518 /* write RTSP TCP header */
2520 header[1] = interleaved_index;
2521 header[2] = len >> 8;
2523 avio_write(pb, header, 4);
2524 /* write RTP packet data */
2526 avio_write(pb, c->buffer_ptr, len);
2527 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2528 /* prepare asynchronous TCP sending */
2529 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2530 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2531 c->buffer_ptr += len;
2533 /* send everything we can NOW */
2534 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2535 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2537 rtsp_c->packet_buffer_ptr += len;
2538 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2539 /* if we could not send all the data, we will
2540 send it later, so a new state is needed to
2541 "lock" the RTSP TCP connection */
2542 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2545 /* all data has been sent */
2546 av_freep(&c->packet_buffer);
2548 /* send RTP packet directly in UDP */
2550 url_write(c->rtp_handles[c->packet_stream_index],
2551 c->buffer_ptr, len);
2552 c->buffer_ptr += len;
2553 /* here we continue as we can send several packets per 10 ms slot */
2556 /* TCP data output */
2557 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2559 if (ff_neterrno() != AVERROR(EAGAIN) &&
2560 ff_neterrno() != AVERROR(EINTR))
2561 /* error : close connection */
2566 c->buffer_ptr += len;
2568 c->data_count += len;
2569 update_datarate(&c->datarate, c->data_count);
2571 c->stream->bytes_served += len;
2579 static int http_start_receive_data(HTTPContext *c)
2583 if (c->stream->feed_opened)
2586 /* Don't permit writing to this one */
2587 if (c->stream->readonly)
2591 fd = open(c->stream->feed_filename, O_RDWR);
2593 http_log("Error opening feeder file: %s\n", strerror(errno));
2598 if (c->stream->truncate) {
2599 /* truncate feed file */
2600 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2601 ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2602 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2604 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2605 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2610 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2611 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2612 lseek(fd, 0, SEEK_SET);
2614 /* init buffer input */
2615 c->buffer_ptr = c->buffer;
2616 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2617 c->stream->feed_opened = 1;
2618 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2622 static int http_receive_data(HTTPContext *c)
2625 int len, loop_run = 0;
2627 while (c->chunked_encoding && !c->chunk_size &&
2628 c->buffer_end > c->buffer_ptr) {
2629 /* read chunk header, if present */
2630 len = recv(c->fd, c->buffer_ptr, 1, 0);
2633 if (ff_neterrno() != AVERROR(EAGAIN) &&
2634 ff_neterrno() != AVERROR(EINTR))
2635 /* error : close connection */
2638 } else if (len == 0) {
2639 /* end of connection : close it */
2641 } else if (c->buffer_ptr - c->buffer >= 2 &&
2642 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2643 c->chunk_size = strtol(c->buffer, 0, 16);
2644 if (c->chunk_size == 0) // end of stream
2646 c->buffer_ptr = c->buffer;
2648 } else if (++loop_run > 10) {
2649 /* no chunk header, abort */
2656 if (c->buffer_end > c->buffer_ptr) {
2657 len = recv(c->fd, c->buffer_ptr,
2658 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2660 if (ff_neterrno() != AVERROR(EAGAIN) &&
2661 ff_neterrno() != AVERROR(EINTR))
2662 /* error : close connection */
2664 } else if (len == 0)
2665 /* end of connection : close it */
2668 c->chunk_size -= len;
2669 c->buffer_ptr += len;
2670 c->data_count += len;
2671 update_datarate(&c->datarate, c->data_count);
2675 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2676 if (c->buffer[0] != 'f' ||
2677 c->buffer[1] != 'm') {
2678 http_log("Feed stream has become desynchronized -- disconnecting\n");
2683 if (c->buffer_ptr >= c->buffer_end) {
2684 FFStream *feed = c->stream;
2685 /* a packet has been received : write it in the store, except
2687 if (c->data_count > FFM_PACKET_SIZE) {
2689 // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2690 /* XXX: use llseek or url_seek */
2691 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2692 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2693 http_log("Error writing to feed file: %s\n", strerror(errno));
2697 feed->feed_write_index += FFM_PACKET_SIZE;
2698 /* update file size */
2699 if (feed->feed_write_index > c->stream->feed_size)
2700 feed->feed_size = feed->feed_write_index;
2702 /* handle wrap around if max file size reached */
2703 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2704 feed->feed_write_index = FFM_PACKET_SIZE;
2707 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2708 http_log("Error writing index to feed file: %s\n", strerror(errno));
2712 /* wake up any waiting connections */
2713 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2714 if (c1->state == HTTPSTATE_WAIT_FEED &&
2715 c1->stream->feed == c->stream->feed)
2716 c1->state = HTTPSTATE_SEND_DATA;
2719 /* We have a header in our hands that contains useful data */
2720 AVFormatContext *s = avformat_alloc_context();
2722 AVInputFormat *fmt_in;
2728 /* use feed output format name to find corresponding input format */
2729 fmt_in = av_find_input_format(feed->fmt->name);
2733 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2734 0, NULL, NULL, NULL, NULL);
2738 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2743 /* Now we have the actual streams */
2744 if (s->nb_streams != feed->nb_streams) {
2745 avformat_close_input(&s);
2747 http_log("Feed '%s' stream number does not match registered feed\n",
2748 c->stream->feed_filename);
2752 for (i = 0; i < s->nb_streams; i++) {
2753 AVStream *fst = feed->streams[i];
2754 AVStream *st = s->streams[i];
2755 avcodec_copy_context(fst->codec, st->codec);
2758 avformat_close_input(&s);
2761 c->buffer_ptr = c->buffer;
2766 c->stream->feed_opened = 0;
2768 /* wake up any waiting connections to stop waiting for feed */
2769 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2770 if (c1->state == HTTPSTATE_WAIT_FEED &&
2771 c1->stream->feed == c->stream->feed)
2772 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2777 /********************************************************************/
2780 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2787 switch(error_number) {
2788 case RTSP_STATUS_OK:
2791 case RTSP_STATUS_METHOD:
2792 str = "Method Not Allowed";
2794 case RTSP_STATUS_BANDWIDTH:
2795 str = "Not Enough Bandwidth";
2797 case RTSP_STATUS_SESSION:
2798 str = "Session Not Found";
2800 case RTSP_STATUS_STATE:
2801 str = "Method Not Valid in This State";
2803 case RTSP_STATUS_AGGREGATE:
2804 str = "Aggregate operation not allowed";
2806 case RTSP_STATUS_ONLY_AGGREGATE:
2807 str = "Only aggregate operation allowed";
2809 case RTSP_STATUS_TRANSPORT:
2810 str = "Unsupported transport";
2812 case RTSP_STATUS_INTERNAL:
2813 str = "Internal Server Error";
2815 case RTSP_STATUS_SERVICE:
2816 str = "Service Unavailable";
2818 case RTSP_STATUS_VERSION:
2819 str = "RTSP Version not supported";
2822 str = "Unknown Error";
2826 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2827 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2829 /* output GMT time */
2832 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2833 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2836 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2838 rtsp_reply_header(c, error_number);
2839 avio_printf(c->pb, "\r\n");
2842 static int rtsp_parse_request(HTTPContext *c)
2844 const char *p, *p1, *p2;
2850 RTSPMessageHeader header1, *header = &header1;
2852 c->buffer_ptr[0] = '\0';
2855 get_word(cmd, sizeof(cmd), &p);
2856 get_word(url, sizeof(url), &p);
2857 get_word(protocol, sizeof(protocol), &p);
2859 av_strlcpy(c->method, cmd, sizeof(c->method));
2860 av_strlcpy(c->url, url, sizeof(c->url));
2861 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2863 if (avio_open_dyn_buf(&c->pb) < 0) {
2864 /* XXX: cannot do more */
2865 c->pb = NULL; /* safety */
2869 /* check version name */
2870 if (strcmp(protocol, "RTSP/1.0") != 0) {
2871 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2875 /* parse each header line */
2876 memset(header, 0, sizeof(*header));
2877 /* skip to next line */
2878 while (*p != '\n' && *p != '\0')
2882 while (*p != '\0') {
2883 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2887 if (p2 > p && p2[-1] == '\r')
2889 /* skip empty line */
2893 if (len > sizeof(line) - 1)
2894 len = sizeof(line) - 1;
2895 memcpy(line, p, len);
2897 ff_rtsp_parse_line(header, line, NULL, NULL);
2901 /* handle sequence number */
2902 c->seq = header->seq;
2904 if (!strcmp(cmd, "DESCRIBE"))
2905 rtsp_cmd_describe(c, url);
2906 else if (!strcmp(cmd, "OPTIONS"))
2907 rtsp_cmd_options(c, url);
2908 else if (!strcmp(cmd, "SETUP"))
2909 rtsp_cmd_setup(c, url, header);
2910 else if (!strcmp(cmd, "PLAY"))
2911 rtsp_cmd_play(c, url, header);
2912 else if (!strcmp(cmd, "PAUSE"))
2913 rtsp_cmd_pause(c, url, header);
2914 else if (!strcmp(cmd, "TEARDOWN"))
2915 rtsp_cmd_teardown(c, url, header);
2917 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2920 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2921 c->pb = NULL; /* safety */
2923 /* XXX: cannot do more */
2926 c->buffer_ptr = c->pb_buffer;
2927 c->buffer_end = c->pb_buffer + len;
2928 c->state = RTSPSTATE_SEND_REPLY;
2932 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2933 struct in_addr my_ip)
2935 AVFormatContext *avc;
2936 AVStream *avs = NULL;
2939 avc = avformat_alloc_context();
2943 av_dict_set(&avc->metadata, "title",
2944 stream->title[0] ? stream->title : "No Title", 0);
2945 avc->nb_streams = stream->nb_streams;
2946 if (stream->is_multicast) {
2947 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2948 inet_ntoa(stream->multicast_ip),
2949 stream->multicast_port, stream->multicast_ttl);
2951 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2954 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2955 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2957 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2958 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2961 for(i = 0; i < stream->nb_streams; i++) {
2962 avc->streams[i] = &avs[i];
2963 avc->streams[i]->codec = stream->streams[i]->codec;
2965 *pbuffer = av_mallocz(2048);
2966 av_sdp_create(&avc, 1, *pbuffer, 2048);
2969 av_free(avc->streams);
2970 av_dict_free(&avc->metadata);
2974 return strlen(*pbuffer);
2977 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2979 // rtsp_reply_header(c, RTSP_STATUS_OK);
2980 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2981 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2982 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2983 avio_printf(c->pb, "\r\n");
2986 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2992 int content_length, len;
2993 struct sockaddr_in my_addr;
2995 /* find which url is asked */
2996 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3001 for(stream = first_stream; stream != NULL; stream = stream->next) {
3002 if (!stream->is_feed &&
3003 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3004 !strcmp(path, stream->filename)) {
3008 /* no stream found */
3009 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3013 /* prepare the media description in sdp format */
3015 /* get the host IP */
3016 len = sizeof(my_addr);
3017 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3018 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3019 if (content_length < 0) {
3020 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3023 rtsp_reply_header(c, RTSP_STATUS_OK);
3024 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3025 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3026 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3027 avio_printf(c->pb, "\r\n");
3028 avio_write(c->pb, content, content_length);
3032 static HTTPContext *find_rtp_session(const char *session_id)
3036 if (session_id[0] == '\0')
3039 for(c = first_http_ctx; c != NULL; c = c->next) {
3040 if (!strcmp(c->session_id, session_id))
3046 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3048 RTSPTransportField *th;
3051 for(i=0;i<h->nb_transports;i++) {
3052 th = &h->transports[i];
3053 if (th->lower_transport == lower_transport)
3059 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3060 RTSPMessageHeader *h)
3063 int stream_index, rtp_port, rtcp_port;
3068 RTSPTransportField *th;
3069 struct sockaddr_in dest_addr;
3070 RTSPActionServerSetup setup;
3072 /* find which url is asked */
3073 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3078 /* now check each stream */
3079 for(stream = first_stream; stream != NULL; stream = stream->next) {
3080 if (!stream->is_feed &&
3081 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3082 /* accept aggregate filenames only if single stream */
3083 if (!strcmp(path, stream->filename)) {
3084 if (stream->nb_streams != 1) {
3085 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3092 for(stream_index = 0; stream_index < stream->nb_streams;
3094 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3095 stream->filename, stream_index);
3096 if (!strcmp(path, buf))
3101 /* no stream found */
3102 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3106 /* generate session id if needed */
3107 if (h->session_id[0] == '\0')
3108 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3109 av_lfg_get(&random_state), av_lfg_get(&random_state));
3111 /* find rtp session, and create it if none found */
3112 rtp_c = find_rtp_session(h->session_id);
3114 /* always prefer UDP */
3115 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3117 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3119 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3124 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3125 th->lower_transport);
3127 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3131 /* open input stream */
3132 if (open_input_stream(rtp_c, "") < 0) {
3133 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3138 /* test if stream is OK (test needed because several SETUP needs
3139 to be done for a given file) */
3140 if (rtp_c->stream != stream) {
3141 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3145 /* test if stream is already set up */
3146 if (rtp_c->rtp_ctx[stream_index]) {
3147 rtsp_reply_error(c, RTSP_STATUS_STATE);
3151 /* check transport */
3152 th = find_transport(h, rtp_c->rtp_protocol);
3153 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3154 th->client_port_min <= 0)) {
3155 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3159 /* setup default options */
3160 setup.transport_option[0] = '\0';
3161 dest_addr = rtp_c->from_addr;
3162 dest_addr.sin_port = htons(th->client_port_min);
3165 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3166 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3170 /* now everything is OK, so we can send the connection parameters */
3171 rtsp_reply_header(c, RTSP_STATUS_OK);
3173 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3175 switch(rtp_c->rtp_protocol) {
3176 case RTSP_LOWER_TRANSPORT_UDP:
3177 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3178 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3179 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3180 "client_port=%d-%d;server_port=%d-%d",
3181 th->client_port_min, th->client_port_max,
3182 rtp_port, rtcp_port);
3184 case RTSP_LOWER_TRANSPORT_TCP:
3185 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3186 stream_index * 2, stream_index * 2 + 1);
3191 if (setup.transport_option[0] != '\0')
3192 avio_printf(c->pb, ";%s", setup.transport_option);
3193 avio_printf(c->pb, "\r\n");
3196 avio_printf(c->pb, "\r\n");
3200 /* find an rtp connection by using the session ID. Check consistency
3202 static HTTPContext *find_rtp_session_with_url(const char *url,
3203 const char *session_id)
3211 rtp_c = find_rtp_session(session_id);
3215 /* find which url is asked */
3216 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3220 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3221 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3222 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3223 rtp_c->stream->filename, s);
3224 if(!strncmp(path, buf, sizeof(buf))) {
3225 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3230 if (len > 0 && path[len - 1] == '/' &&
3231 !strncmp(path, rtp_c->stream->filename, len - 1))
3236 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3240 rtp_c = find_rtp_session_with_url(url, h->session_id);
3242 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3246 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3247 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3248 rtp_c->state != HTTPSTATE_READY) {
3249 rtsp_reply_error(c, RTSP_STATUS_STATE);
3253 rtp_c->state = HTTPSTATE_SEND_DATA;
3255 /* now everything is OK, so we can send the connection parameters */
3256 rtsp_reply_header(c, RTSP_STATUS_OK);
3258 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3259 avio_printf(c->pb, "\r\n");
3262 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3266 rtp_c = find_rtp_session_with_url(url, h->session_id);
3268 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3272 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3273 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3274 rtsp_reply_error(c, RTSP_STATUS_STATE);
3278 rtp_c->state = HTTPSTATE_READY;
3279 rtp_c->first_pts = AV_NOPTS_VALUE;
3280 /* now everything is OK, so we can send the connection parameters */
3281 rtsp_reply_header(c, RTSP_STATUS_OK);
3283 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3284 avio_printf(c->pb, "\r\n");
3287 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3291 rtp_c = find_rtp_session_with_url(url, h->session_id);
3293 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3297 /* now everything is OK, so we can send the connection parameters */
3298 rtsp_reply_header(c, RTSP_STATUS_OK);
3300 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3301 avio_printf(c->pb, "\r\n");
3303 /* abort the session */
3304 close_connection(rtp_c);
3308 /********************************************************************/
3311 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3312 FFStream *stream, const char *session_id,
3313 enum RTSPLowerTransport rtp_protocol)
3315 HTTPContext *c = NULL;
3316 const char *proto_str;
3318 /* XXX: should output a warning page when coming
3319 close to the connection limit */
3320 if (nb_connections >= nb_max_connections)
3323 /* add a new connection */
3324 c = av_mallocz(sizeof(HTTPContext));
3329 c->poll_entry = NULL;
3330 c->from_addr = *from_addr;
3331 c->buffer_size = IOBUFFER_INIT_SIZE;
3332 c->buffer = av_malloc(c->buffer_size);
3337 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3338 c->state = HTTPSTATE_READY;
3339 c->is_packetized = 1;
3340 c->rtp_protocol = rtp_protocol;
3342 /* protocol is shown in statistics */
3343 switch(c->rtp_protocol) {
3344 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3345 proto_str = "MCAST";
3347 case RTSP_LOWER_TRANSPORT_UDP:
3350 case RTSP_LOWER_TRANSPORT_TCP:
3357 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3358 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3360 current_bandwidth += stream->bandwidth;
3362 c->next = first_http_ctx;
3374 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3375 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3377 static int rtp_new_av_stream(HTTPContext *c,
3378 int stream_index, struct sockaddr_in *dest_addr,
3379 HTTPContext *rtsp_c)
3381 AVFormatContext *ctx;
3384 URLContext *h = NULL;
3386 int max_packet_size;
3388 /* now we can open the relevant output stream */
3389 ctx = avformat_alloc_context();
3392 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3394 st = av_mallocz(sizeof(AVStream));
3397 ctx->nb_streams = 1;
3398 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3401 ctx->streams[0] = st;
3403 if (!c->stream->feed ||
3404 c->stream->feed == c->stream)
3405 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3408 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3410 st->priv_data = NULL;
3412 /* build destination RTP address */
3413 ipaddr = inet_ntoa(dest_addr->sin_addr);
3415 switch(c->rtp_protocol) {
3416 case RTSP_LOWER_TRANSPORT_UDP:
3417 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3420 /* XXX: also pass as parameter to function ? */
3421 if (c->stream->is_multicast) {
3423 ttl = c->stream->multicast_ttl;
3426 snprintf(ctx->filename, sizeof(ctx->filename),
3427 "rtp://%s:%d?multicast=1&ttl=%d",
3428 ipaddr, ntohs(dest_addr->sin_port), ttl);
3430 snprintf(ctx->filename, sizeof(ctx->filename),
3431 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3434 if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
3436 c->rtp_handles[stream_index] = h;
3437 max_packet_size = url_get_max_packet_size(h);
3439 case RTSP_LOWER_TRANSPORT_TCP:
3442 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3448 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3449 ipaddr, ntohs(dest_addr->sin_port),
3450 c->stream->filename, stream_index, c->protocol);
3452 /* normally, no packets should be output here, but the packet size may be checked */
3453 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3454 /* XXX: close stream */
3457 if (avformat_write_header(ctx, NULL) < 0) {
3464 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3467 c->rtp_ctx[stream_index] = ctx;
3471 /********************************************************************/
3472 /* ffserver initialization */
3474 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3478 fst = av_mallocz(sizeof(AVStream));
3482 fst->codec = avcodec_alloc_context3(NULL);
3483 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3484 if (codec->extradata_size) {
3485 fst->codec->extradata = av_malloc(codec->extradata_size);
3486 memcpy(fst->codec->extradata, codec->extradata,
3487 codec->extradata_size);
3490 /* live streams must use the actual feed's codec since it may be
3491 * updated later to carry extradata needed by the streams.
3495 fst->priv_data = av_mallocz(sizeof(FeedData));
3496 fst->index = stream->nb_streams;
3497 av_set_pts_info(fst, 33, 1, 90000);
3498 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3499 stream->streams[stream->nb_streams++] = fst;
3503 /* return the stream number in the feed */
3504 static int add_av_stream(FFStream *feed, AVStream *st)
3507 AVCodecContext *av, *av1;
3511 for(i=0;i<feed->nb_streams;i++) {
3512 st = feed->streams[i];
3514 if (av1->codec_id == av->codec_id &&
3515 av1->codec_type == av->codec_type &&
3516 av1->bit_rate == av->bit_rate) {
3518 switch(av->codec_type) {
3519 case AVMEDIA_TYPE_AUDIO:
3520 if (av1->channels == av->channels &&
3521 av1->sample_rate == av->sample_rate)
3524 case AVMEDIA_TYPE_VIDEO:
3525 if (av1->width == av->width &&
3526 av1->height == av->height &&
3527 av1->time_base.den == av->time_base.den &&
3528 av1->time_base.num == av->time_base.num &&
3529 av1->gop_size == av->gop_size)
3538 fst = add_av_stream1(feed, av, 0);
3541 return feed->nb_streams - 1;
3544 static void remove_stream(FFStream *stream)
3548 while (*ps != NULL) {
3556 /* specific mpeg4 handling : we extract the raw parameters */
3557 static void extract_mpeg4_header(AVFormatContext *infile)
3559 int mpeg4_count, i, size;
3565 for(i=0;i<infile->nb_streams;i++) {
3566 st = infile->streams[i];
3567 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3568 st->codec->extradata_size == 0) {
3575 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3576 while (mpeg4_count > 0) {
3577 if (av_read_packet(infile, &pkt) < 0)
3579 st = infile->streams[pkt.stream_index];
3580 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3581 st->codec->extradata_size == 0) {
3582 av_freep(&st->codec->extradata);
3583 /* fill extradata with the header */
3584 /* XXX: we make hard suppositions here ! */
3586 while (p < pkt.data + pkt.size - 4) {
3587 /* stop when vop header is found */
3588 if (p[0] == 0x00 && p[1] == 0x00 &&
3589 p[2] == 0x01 && p[3] == 0xb6) {
3590 size = p - pkt.data;
3591 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3592 st->codec->extradata = av_malloc(size);
3593 st->codec->extradata_size = size;
3594 memcpy(st->codec->extradata, pkt.data, size);
3601 av_free_packet(&pkt);
3605 /* compute the needed AVStream for each file */
3606 static void build_file_streams(void)
3608 FFStream *stream, *stream_next;
3611 /* gather all streams */
3612 for(stream = first_stream; stream != NULL; stream = stream_next) {
3613 AVFormatContext *infile = NULL;
3614 stream_next = stream->next;
3615 if (stream->stream_type == STREAM_TYPE_LIVE &&
3617 /* the stream comes from a file */
3618 /* try to open the file */
3620 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3621 /* specific case : if transport stream output to RTP,
3622 we use a raw transport stream reader */
3623 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3626 http_log("Opening file '%s'\n", stream->feed_filename);
3627 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3628 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3629 /* remove stream (no need to spend more time on it) */
3631 remove_stream(stream);
3633 /* find all the AVStreams inside and reference them in
3635 if (avformat_find_stream_info(infile, NULL) < 0) {
3636 http_log("Could not find codec parameters from '%s'\n",
3637 stream->feed_filename);
3638 avformat_close_input(&infile);
3641 extract_mpeg4_header(infile);
3643 for(i=0;i<infile->nb_streams;i++)
3644 add_av_stream1(stream, infile->streams[i]->codec, 1);
3646 avformat_close_input(&infile);
3652 /* compute the needed AVStream for each feed */
3653 static void build_feed_streams(void)
3655 FFStream *stream, *feed;
3658 /* gather all streams */
3659 for(stream = first_stream; stream != NULL; stream = stream->next) {
3660 feed = stream->feed;
3662 if (stream->is_feed) {
3663 for(i=0;i<stream->nb_streams;i++)
3664 stream->feed_streams[i] = i;
3666 /* we handle a stream coming from a feed */
3667 for(i=0;i<stream->nb_streams;i++)
3668 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3673 /* create feed files if needed */
3674 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3677 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3678 /* See if it matches */
3679 AVFormatContext *s = NULL;
3682 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3683 /* Now see if it matches */
3684 if (s->nb_streams == feed->nb_streams) {
3686 for(i=0;i<s->nb_streams;i++) {
3688 sf = feed->streams[i];
3691 if (sf->index != ss->index ||
3693 http_log("Index & Id do not match for stream %d (%s)\n",
3694 i, feed->feed_filename);
3697 AVCodecContext *ccf, *ccs;
3701 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3703 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3704 http_log("Codecs do not match for stream %d\n", i);
3706 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3707 http_log("Codec bitrates do not match for stream %d\n", i);
3709 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3710 if (CHECK_CODEC(time_base.den) ||
3711 CHECK_CODEC(time_base.num) ||
3712 CHECK_CODEC(width) ||
3713 CHECK_CODEC(height)) {
3714 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3717 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3718 if (CHECK_CODEC(sample_rate) ||
3719 CHECK_CODEC(channels) ||
3720 CHECK_CODEC(frame_size)) {
3721 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3725 http_log("Unknown codec type\n");
3733 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3734 feed->feed_filename, s->nb_streams, feed->nb_streams);
3736 avformat_close_input(&s);
3738 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3739 feed->feed_filename);
3742 if (feed->readonly) {
3743 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3744 feed->feed_filename);
3747 unlink(feed->feed_filename);
3750 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3751 AVFormatContext s1 = {0}, *s = &s1;
3753 if (feed->readonly) {
3754 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3755 feed->feed_filename);
3759 /* only write the header of the ffm file */
3760 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3761 http_log("Could not open output feed file '%s'\n",
3762 feed->feed_filename);
3765 s->oformat = feed->fmt;
3766 s->nb_streams = feed->nb_streams;
3767 s->streams = feed->streams;
3768 if (avformat_write_header(s, NULL) < 0) {
3769 http_log("Container doesn't supports the required parameters\n");
3772 /* XXX: need better api */
3773 av_freep(&s->priv_data);
3776 /* get feed size and write index */
3777 fd = open(feed->feed_filename, O_RDONLY);
3779 http_log("Could not open output feed file '%s'\n",
3780 feed->feed_filename);
3784 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3785 feed->feed_size = lseek(fd, 0, SEEK_END);
3786 /* ensure that we do not wrap before the end of file */
3787 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3788 feed->feed_max_size = feed->feed_size;
3794 /* compute the bandwidth used by each stream */
3795 static void compute_bandwidth(void)
3801 for(stream = first_stream; stream != NULL; stream = stream->next) {
3803 for(i=0;i<stream->nb_streams;i++) {
3804 AVStream *st = stream->streams[i];
3805 switch(st->codec->codec_type) {
3806 case AVMEDIA_TYPE_AUDIO:
3807 case AVMEDIA_TYPE_VIDEO:
3808 bandwidth += st->codec->bit_rate;
3814 stream->bandwidth = (bandwidth + 999) / 1000;
3818 /* add a codec and set the default parameters */
3819 static void add_codec(FFStream *stream, AVCodecContext *av)
3823 /* compute default parameters */
3824 switch(av->codec_type) {
3825 case AVMEDIA_TYPE_AUDIO:
3826 if (av->bit_rate == 0)
3827 av->bit_rate = 64000;
3828 if (av->sample_rate == 0)
3829 av->sample_rate = 22050;
3830 if (av->channels == 0)
3833 case AVMEDIA_TYPE_VIDEO:
3834 if (av->bit_rate == 0)
3835 av->bit_rate = 64000;
3836 if (av->time_base.num == 0){
3837 av->time_base.den = 5;
3838 av->time_base.num = 1;
3840 if (av->width == 0 || av->height == 0) {
3844 /* Bitrate tolerance is less for streaming */
3845 if (av->bit_rate_tolerance == 0)
3846 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3847 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3852 if (av->max_qdiff == 0)
3854 av->qcompress = 0.5;
3857 if (!av->nsse_weight)
3858 av->nsse_weight = 8;
3860 av->frame_skip_cmp = FF_CMP_DCTMAX;
3862 av->me_method = ME_EPZS;
3863 av->rc_buffer_aggressivity = 1.0;
3866 av->rc_eq = "tex^qComp";
3867 if (!av->i_quant_factor)
3868 av->i_quant_factor = -0.8;
3869 if (!av->b_quant_factor)
3870 av->b_quant_factor = 1.25;
3871 if (!av->b_quant_offset)
3872 av->b_quant_offset = 1.25;
3873 if (!av->rc_max_rate)
3874 av->rc_max_rate = av->bit_rate * 2;
3876 if (av->rc_max_rate && !av->rc_buffer_size) {
3877 av->rc_buffer_size = av->rc_max_rate;
3886 st = av_mallocz(sizeof(AVStream));
3889 st->codec = avcodec_alloc_context3(NULL);
3890 stream->streams[stream->nb_streams++] = st;
3891 memcpy(st->codec, av, sizeof(AVCodecContext));
3894 static enum CodecID opt_audio_codec(const char *arg)
3896 AVCodec *p= avcodec_find_encoder_by_name(arg);
3898 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3899 return CODEC_ID_NONE;
3904 static enum CodecID opt_video_codec(const char *arg)
3906 AVCodec *p= avcodec_find_encoder_by_name(arg);
3908 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3909 return CODEC_ID_NONE;
3914 /* simplistic plugin support */
3917 static void load_module(const char *filename)
3920 void (*init_func)(void);
3921 dll = dlopen(filename, RTLD_NOW);
3923 fprintf(stderr, "Could not load module '%s' - %s\n",
3924 filename, dlerror());
3928 init_func = dlsym(dll, "ffserver_module_init");
3931 "%s: init function 'ffserver_module_init()' not found\n",
3940 static int ffserver_opt_default(const char *opt, const char *arg,
3941 AVCodecContext *avctx, int type)
3944 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3946 ret = av_opt_set(avctx, opt, arg, 0);
3950 static int ffserver_opt_preset(const char *arg,
3951 AVCodecContext *avctx, int type,
3952 enum CodecID *audio_id, enum CodecID *video_id)
3955 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3957 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3959 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3960 codec ? codec->name : NULL))) {
3961 fprintf(stderr, "File for preset '%s' not found\n", arg);
3966 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3967 if(line[0] == '#' && !e)
3969 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3971 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3975 if(!strcmp(tmp, "acodec")){
3976 *audio_id = opt_audio_codec(tmp2);
3977 }else if(!strcmp(tmp, "vcodec")){
3978 *video_id = opt_video_codec(tmp2);
3979 }else if(!strcmp(tmp, "scodec")){
3980 /* opt_subtitle_codec(tmp2); */
3981 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3982 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3993 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3994 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 *errors, const char *fmt, ...)
4016 fprintf(stderr, "%s:%d: ", filename, line_num);
4017 vfprintf(stderr, fmt, vl);
4023 static int parse_ffconfig(const char *filename)
4030 int val, errors, line_num;
4031 FFStream **last_stream, *stream, *redirect;
4032 FFStream **last_feed, *feed, *s;
4033 AVCodecContext audio_enc, video_enc;
4034 enum CodecID audio_id, video_id;
4036 f = fopen(filename, "r");
4044 first_stream = NULL;
4045 last_stream = &first_stream;
4047 last_feed = &first_feed;
4051 audio_id = CODEC_ID_NONE;
4052 video_id = CODEC_ID_NONE;
4054 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4056 if (fgets(line, sizeof(line), f) == NULL)
4062 if (*p == '\0' || *p == '#')
4065 get_arg(cmd, sizeof(cmd), &p);
4067 if (!av_strcasecmp(cmd, "Port")) {
4068 get_arg(arg, sizeof(arg), &p);
4070 if (val < 1 || val > 65536) {
4071 ERROR("Invalid_port: %s\n", arg);
4073 my_http_addr.sin_port = htons(val);
4074 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4075 get_arg(arg, sizeof(arg), &p);
4076 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4077 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4079 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4080 ffserver_daemon = 0;
4081 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4082 get_arg(arg, sizeof(arg), &p);
4084 if (val < 1 || val > 65536) {
4085 ERROR("%s:%d: Invalid port: %s\n", arg);
4087 my_rtsp_addr.sin_port = htons(atoi(arg));
4088 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4089 get_arg(arg, sizeof(arg), &p);
4090 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4091 ERROR("Invalid host/IP address: %s\n", arg);
4093 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4094 get_arg(arg, sizeof(arg), &p);
4096 if (val < 1 || val > 65536) {
4097 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4099 nb_max_http_connections = val;
4100 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4101 get_arg(arg, sizeof(arg), &p);
4103 if (val < 1 || val > nb_max_http_connections) {
4104 ERROR("Invalid MaxClients: %s\n", arg);
4106 nb_max_connections = val;
4108 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4110 get_arg(arg, sizeof(arg), &p);
4112 if (llval < 10 || llval > 10000000) {
4113 ERROR("Invalid MaxBandwidth: %s\n", arg);
4115 max_bandwidth = llval;
4116 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4117 if (!ffserver_debug)
4118 get_arg(logfilename, sizeof(logfilename), &p);
4119 } else if (!av_strcasecmp(cmd, "<Feed")) {
4120 /*********************************************/
4121 /* Feed related options */
4123 if (stream || feed) {
4124 ERROR("Already in a tag\n");
4126 feed = av_mallocz(sizeof(FFStream));
4127 get_arg(feed->filename, sizeof(feed->filename), &p);
4128 q = strrchr(feed->filename, '>');
4132 for (s = first_feed; s; s = s->next) {
4133 if (!strcmp(feed->filename, s->filename)) {
4134 ERROR("Feed '%s' already registered\n", s->filename);
4138 feed->fmt = av_guess_format("ffm", NULL, NULL);
4139 /* defaut feed file */
4140 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4141 "/tmp/%s.ffm", feed->filename);
4142 feed->feed_max_size = 5 * 1024 * 1024;
4144 feed->feed = feed; /* self feeding :-) */
4146 /* add in stream list */
4147 *last_stream = feed;
4148 last_stream = &feed->next;
4149 /* add in feed list */
4151 last_feed = &feed->next_feed;
4153 } else if (!av_strcasecmp(cmd, "Launch")) {
4157 feed->child_argv = av_mallocz(64 * sizeof(char *));
4159 for (i = 0; i < 62; i++) {
4160 get_arg(arg, sizeof(arg), &p);
4164 feed->child_argv[i] = av_strdup(arg);
4167 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4169 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4171 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4172 inet_ntoa(my_http_addr.sin_addr),
4173 ntohs(my_http_addr.sin_port), feed->filename);
4175 } else if (!av_strcasecmp(cmd, "ReadOnlyFile")) {
4177 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4179 } else if (stream) {
4180 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4182 } else if (!av_strcasecmp(cmd, "File")) {
4184 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4186 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4187 } else if (!av_strcasecmp(cmd, "Truncate")) {
4189 get_arg(arg, sizeof(arg), &p);
4190 feed->truncate = strtod(arg, NULL);
4192 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4197 get_arg(arg, sizeof(arg), &p);
4199 fsize = strtod(p1, &p1);
4200 switch(toupper(*p1)) {
4205 fsize *= 1024 * 1024;
4208 fsize *= 1024 * 1024 * 1024;
4211 feed->feed_max_size = (int64_t)fsize;
4212 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4213 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4216 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4218 ERROR("No corresponding <Feed> for </Feed>\n");
4221 } else if (!av_strcasecmp(cmd, "<Stream")) {
4222 /*********************************************/
4223 /* Stream related options */
4225 if (stream || feed) {
4226 ERROR("Already in a tag\n");
4229 stream = av_mallocz(sizeof(FFStream));
4230 get_arg(stream->filename, sizeof(stream->filename), &p);
4231 q = strrchr(stream->filename, '>');
4235 for (s = first_stream; s; s = s->next) {
4236 if (!strcmp(stream->filename, s->filename)) {
4237 ERROR("Stream '%s' already registered\n", s->filename);
4241 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4242 avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4243 avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4245 audio_id = CODEC_ID_NONE;
4246 video_id = CODEC_ID_NONE;
4248 audio_id = stream->fmt->audio_codec;
4249 video_id = stream->fmt->video_codec;
4252 *last_stream = stream;
4253 last_stream = &stream->next;
4255 } else if (!av_strcasecmp(cmd, "Feed")) {
4256 get_arg(arg, sizeof(arg), &p);
4261 while (sfeed != NULL) {
4262 if (!strcmp(sfeed->filename, arg))
4264 sfeed = sfeed->next_feed;
4267 ERROR("feed '%s' not defined\n", arg);
4269 stream->feed = sfeed;
4271 } else if (!av_strcasecmp(cmd, "Format")) {
4272 get_arg(arg, sizeof(arg), &p);
4274 if (!strcmp(arg, "status")) {
4275 stream->stream_type = STREAM_TYPE_STATUS;
4278 stream->stream_type = STREAM_TYPE_LIVE;
4279 /* jpeg cannot be used here, so use single frame jpeg */
4280 if (!strcmp(arg, "jpeg"))
4281 strcpy(arg, "mjpeg");
4282 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4284 ERROR("Unknown Format: %s\n", arg);
4288 audio_id = stream->fmt->audio_codec;
4289 video_id = stream->fmt->video_codec;
4292 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4293 get_arg(arg, sizeof(arg), &p);
4295 stream->ifmt = av_find_input_format(arg);
4296 if (!stream->ifmt) {
4297 ERROR("Unknown input format: %s\n", arg);
4300 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4301 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4302 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4304 ERROR("FaviconURL only permitted for status streams\n");
4306 } else if (!av_strcasecmp(cmd, "Author")) {
4308 get_arg(stream->author, sizeof(stream->author), &p);
4309 } else if (!av_strcasecmp(cmd, "Comment")) {
4311 get_arg(stream->comment, sizeof(stream->comment), &p);
4312 } else if (!av_strcasecmp(cmd, "Copyright")) {
4314 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4315 } else if (!av_strcasecmp(cmd, "Title")) {
4317 get_arg(stream->title, sizeof(stream->title), &p);
4318 } else if (!av_strcasecmp(cmd, "Preroll")) {
4319 get_arg(arg, sizeof(arg), &p);
4321 stream->prebuffer = atof(arg) * 1000;
4322 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4324 stream->send_on_key = 1;
4325 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4326 get_arg(arg, sizeof(arg), &p);
4327 audio_id = opt_audio_codec(arg);
4328 if (audio_id == CODEC_ID_NONE) {
4329 ERROR("Unknown AudioCodec: %s\n", arg);
4331 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4332 get_arg(arg, sizeof(arg), &p);
4333 video_id = opt_video_codec(arg);
4334 if (video_id == CODEC_ID_NONE) {
4335 ERROR("Unknown VideoCodec: %s\n", arg);
4337 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4338 get_arg(arg, sizeof(arg), &p);
4340 stream->max_time = atof(arg) * 1000;
4341 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4342 get_arg(arg, sizeof(arg), &p);
4344 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4345 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4346 get_arg(arg, sizeof(arg), &p);
4348 audio_enc.channels = atoi(arg);
4349 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4350 get_arg(arg, sizeof(arg), &p);
4352 audio_enc.sample_rate = atoi(arg);
4353 } else if (!av_strcasecmp(cmd, "AudioQuality")) {
4354 get_arg(arg, sizeof(arg), &p);
4356 // audio_enc.quality = atof(arg) * 1000;
4358 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4360 int minrate, maxrate;
4362 get_arg(arg, sizeof(arg), &p);
4364 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4365 video_enc.rc_min_rate = minrate * 1000;
4366 video_enc.rc_max_rate = maxrate * 1000;
4368 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4371 } else if (!av_strcasecmp(cmd, "Debug")) {
4373 get_arg(arg, sizeof(arg), &p);
4374 video_enc.debug = strtol(arg,0,0);
4376 } else if (!av_strcasecmp(cmd, "Strict")) {
4378 get_arg(arg, sizeof(arg), &p);
4379 video_enc.strict_std_compliance = atoi(arg);
4381 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4383 get_arg(arg, sizeof(arg), &p);
4384 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4386 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4388 get_arg(arg, sizeof(arg), &p);
4389 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4391 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4392 get_arg(arg, sizeof(arg), &p);
4394 video_enc.bit_rate = atoi(arg) * 1000;
4396 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4397 get_arg(arg, sizeof(arg), &p);
4399 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4400 if ((video_enc.width % 16) != 0 ||
4401 (video_enc.height % 16) != 0) {
4402 ERROR("Image size must be a multiple of 16\n");
4405 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4406 get_arg(arg, sizeof(arg), &p);
4408 AVRational frame_rate;
4409 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4410 ERROR("Incorrect frame rate: %s\n", arg);
4412 video_enc.time_base.num = frame_rate.den;
4413 video_enc.time_base.den = frame_rate.num;
4416 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4417 get_arg(arg, sizeof(arg), &p);
4419 video_enc.gop_size = atoi(arg);
4420 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4422 video_enc.gop_size = 1;
4423 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4425 video_enc.mb_decision = FF_MB_DECISION_BITS;
4426 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4428 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4429 video_enc.flags |= CODEC_FLAG_4MV;
4431 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4432 !av_strcasecmp(cmd, "AVOptionAudio")) {
4434 AVCodecContext *avctx;
4436 get_arg(arg, sizeof(arg), &p);
4437 get_arg(arg2, sizeof(arg2), &p);
4438 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4440 type = AV_OPT_FLAG_VIDEO_PARAM;
4443 type = AV_OPT_FLAG_AUDIO_PARAM;
4445 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4446 ERROR("AVOption error: %s %s\n", arg, arg2);
4448 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4449 !av_strcasecmp(cmd, "AVPresetAudio")) {
4450 AVCodecContext *avctx;
4452 get_arg(arg, sizeof(arg), &p);
4453 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4455 video_enc.codec_id = video_id;
4456 type = AV_OPT_FLAG_VIDEO_PARAM;
4459 audio_enc.codec_id = audio_id;
4460 type = AV_OPT_FLAG_AUDIO_PARAM;
4462 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4463 ERROR("AVPreset error: %s\n", arg);
4465 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4466 get_arg(arg, sizeof(arg), &p);
4467 if ((strlen(arg) == 4) && stream)
4468 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4469 } else if (!av_strcasecmp(cmd, "BitExact")) {
4471 video_enc.flags |= CODEC_FLAG_BITEXACT;
4472 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4474 video_enc.dct_algo = FF_DCT_FASTINT;
4475 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4477 video_enc.idct_algo = FF_IDCT_SIMPLE;
4478 } else if (!av_strcasecmp(cmd, "Qscale")) {
4479 get_arg(arg, sizeof(arg), &p);
4481 video_enc.flags |= CODEC_FLAG_QSCALE;
4482 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4484 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4485 get_arg(arg, sizeof(arg), &p);
4487 video_enc.max_qdiff = atoi(arg);
4488 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4489 ERROR("VideoQDiff out of range\n");
4492 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4493 get_arg(arg, sizeof(arg), &p);
4495 video_enc.qmax = atoi(arg);
4496 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4497 ERROR("VideoQMax out of range\n");
4500 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4501 get_arg(arg, sizeof(arg), &p);
4503 video_enc.qmin = atoi(arg);
4504 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4505 ERROR("VideoQMin out of range\n");
4508 } else if (!av_strcasecmp(cmd, "LumaElim")) {
4509 get_arg(arg, sizeof(arg), &p);
4511 video_enc.luma_elim_threshold = atoi(arg);
4512 } else if (!av_strcasecmp(cmd, "ChromaElim")) {
4513 get_arg(arg, sizeof(arg), &p);
4515 video_enc.chroma_elim_threshold = atoi(arg);
4516 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4517 get_arg(arg, sizeof(arg), &p);
4519 video_enc.lumi_masking = atof(arg);
4520 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4521 get_arg(arg, sizeof(arg), &p);
4523 video_enc.dark_masking = atof(arg);
4524 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4525 video_id = CODEC_ID_NONE;
4526 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4527 audio_id = CODEC_ID_NONE;
4528 } else if (!av_strcasecmp(cmd, "ACL")) {
4529 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4530 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4532 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4534 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4535 get_arg(arg, sizeof(arg), &p);
4537 av_freep(&stream->rtsp_option);
4538 stream->rtsp_option = av_strdup(arg);
4540 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4541 get_arg(arg, sizeof(arg), &p);
4543 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4544 ERROR("Invalid host/IP address: %s\n", arg);
4546 stream->is_multicast = 1;
4547 stream->loop = 1; /* default is looping */
4549 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4550 get_arg(arg, sizeof(arg), &p);
4552 stream->multicast_port = atoi(arg);
4553 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4554 get_arg(arg, sizeof(arg), &p);
4556 stream->multicast_ttl = atoi(arg);
4557 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4560 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4562 ERROR("No corresponding <Stream> for </Stream>\n");
4564 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4565 if (audio_id != CODEC_ID_NONE) {
4566 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4567 audio_enc.codec_id = audio_id;
4568 add_codec(stream, &audio_enc);
4570 if (video_id != CODEC_ID_NONE) {
4571 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4572 video_enc.codec_id = video_id;
4573 add_codec(stream, &video_enc);
4578 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4579 /*********************************************/
4581 if (stream || feed || redirect) {
4582 ERROR("Already in a tag\n");
4584 redirect = av_mallocz(sizeof(FFStream));
4585 *last_stream = redirect;
4586 last_stream = &redirect->next;
4588 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4589 q = strrchr(redirect->filename, '>');
4592 redirect->stream_type = STREAM_TYPE_REDIRECT;
4594 } else if (!av_strcasecmp(cmd, "URL")) {
4596 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4597 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4599 ERROR("No corresponding <Redirect> for </Redirect>\n");
4601 if (!redirect->feed_filename[0]) {
4602 ERROR("No URL found for <Redirect>\n");
4606 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4607 get_arg(arg, sizeof(arg), &p);
4611 ERROR("Module support not compiled into this version: '%s'\n", arg);
4614 ERROR("Incorrect keyword: '%s'\n", cmd);
4626 static void handle_child_exit(int sig)
4631 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4634 for (feed = first_feed; feed; feed = feed->next) {
4635 if (feed->pid == pid) {
4636 int uptime = time(0) - feed->pid_start;
4639 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4642 /* Turn off any more restarts */
4643 feed->child_argv = 0;
4648 need_to_start_children = 1;
4651 static void opt_debug(void)
4654 ffserver_daemon = 0;
4655 logfilename[0] = '-';
4658 static int opt_help(const char *opt, const char *arg)
4660 printf("usage: ffserver [options]\n"
4661 "Hyper fast multi format Audio/Video streaming server\n");
4663 show_help_options(options, "Main options:\n", 0, 0);
4667 static const OptionDef options[] = {
4668 #include "cmdutils_common_opts.h"
4669 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4670 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4671 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4675 int main(int argc, char **argv)
4677 struct sigaction sigact;
4679 parse_loglevel(argc, argv, options);
4681 avformat_network_init();
4683 show_banner(argc, argv, options);
4685 my_program_name = argv[0];
4686 my_program_dir = getcwd(0, 0);
4687 ffserver_daemon = 1;
4689 parse_options(NULL, argc, argv, options, NULL);
4691 unsetenv("http_proxy"); /* Kill the http_proxy */
4693 av_lfg_init(&random_state, av_get_random_seed());
4695 memset(&sigact, 0, sizeof(sigact));
4696 sigact.sa_handler = handle_child_exit;
4697 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4698 sigaction(SIGCHLD, &sigact, 0);
4700 if (parse_ffconfig(config_filename) < 0) {
4701 fprintf(stderr, "Incorrect config file - exiting.\n");
4705 /* open log file if needed */
4706 if (logfilename[0] != '\0') {
4707 if (!strcmp(logfilename, "-"))
4710 logfile = fopen(logfilename, "a");
4711 av_log_set_callback(http_av_log);
4714 build_file_streams();
4716 build_feed_streams();
4718 compute_bandwidth();
4720 /* put the process in background and detach it from its TTY */
4721 if (ffserver_daemon) {
4728 } else if (pid > 0) {
4735 open("/dev/null", O_RDWR);
4736 if (strcmp(logfilename, "-") != 0) {
4746 signal(SIGPIPE, SIG_IGN);
4748 if (ffserver_daemon)
4751 if (http_server() < 0) {
4752 http_log("Could not start server\n");