2 * Multiple format streaming server
3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #define closesocket close
29 #include "libavformat/avformat.h"
30 #include "libavformat/ffm.h"
31 #include "libavformat/network.h"
32 #include "libavformat/os_support.h"
33 #include "libavformat/rtpdec.h"
34 #include "libavformat/rtsp.h"
35 // XXX for ffio_open_dyn_packet_buffer, to be removed
36 #include "libavformat/avio_internal.h"
37 #include "libavutil/avstring.h"
38 #include "libavutil/lfg.h"
39 #include "libavutil/dict.h"
40 #include "libavutil/mathematics.h"
41 #include "libavutil/random_seed.h"
42 #include "libavutil/parseutils.h"
43 #include "libavutil/opt.h"
47 #include <sys/ioctl.h>
62 const char program_name[] = "ffserver";
63 const int program_birth_year = 2000;
65 static const OptionDef options[];
68 HTTPSTATE_WAIT_REQUEST,
69 HTTPSTATE_SEND_HEADER,
70 HTTPSTATE_SEND_DATA_HEADER,
71 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
72 HTTPSTATE_SEND_DATA_TRAILER,
73 HTTPSTATE_RECEIVE_DATA,
74 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
77 RTSPSTATE_WAIT_REQUEST,
79 RTSPSTATE_SEND_PACKET,
82 static const char *http_state[] = {
98 #define MAX_STREAMS 20
100 #define IOBUFFER_INIT_SIZE 8192
102 /* timeouts are in ms */
103 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
104 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
106 #define SYNC_TIMEOUT (10 * 1000)
108 typedef struct RTSPActionServerSetup {
110 char transport_option[512];
111 } RTSPActionServerSetup;
114 int64_t count1, count2;
115 int64_t time1, time2;
118 /* context associated with one connection */
119 typedef struct HTTPContext {
120 enum HTTPState state;
121 int fd; /* socket file descriptor */
122 struct sockaddr_in from_addr; /* origin */
123 struct pollfd *poll_entry; /* used when polling */
125 uint8_t *buffer_ptr, *buffer_end;
128 int chunked_encoding;
129 int chunk_size; /* 0 if it needs to be read */
130 struct HTTPContext *next;
131 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
135 /* input format handling */
136 AVFormatContext *fmt_in;
137 int64_t start_time; /* In milliseconds - this wraps fairly often */
138 int64_t first_pts; /* initial pts value */
139 int64_t cur_pts; /* current pts value from the stream in us */
140 int64_t cur_frame_duration; /* duration of the current frame in us */
141 int cur_frame_bytes; /* output frame size, needed to compute
142 the time at which we send each
144 int pts_stream_index; /* stream we choose as clock reference */
145 int64_t cur_clock; /* current clock reference value in us */
146 /* output format handling */
147 struct FFStream *stream;
148 /* -1 is invalid stream */
149 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
150 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
152 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
153 int last_packet_sent; /* true if last data packet was sent */
155 DataRateData datarate;
162 int is_packetized; /* if true, the stream is packetized */
163 int packet_stream_index; /* current stream for output in state machine */
165 /* RTSP state specific */
166 uint8_t *pb_buffer; /* XXX: use that in all the code */
168 int seq; /* RTSP sequence number */
170 /* RTP state specific */
171 enum RTSPLowerTransport rtp_protocol;
172 char session_id[32]; /* session id */
173 AVFormatContext *rtp_ctx[MAX_STREAMS];
175 /* RTP/UDP specific */
176 URLContext *rtp_handles[MAX_STREAMS];
178 /* RTP/TCP specific */
179 struct HTTPContext *rtsp_c;
180 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
183 /* each generated stream is described here */
187 STREAM_TYPE_REDIRECT,
190 enum IPAddressAction {
195 typedef struct IPAddressACL {
196 struct IPAddressACL *next;
197 enum IPAddressAction action;
198 /* These are in host order */
199 struct in_addr first;
203 /* description of each stream of the ffserver.conf file */
204 typedef struct FFStream {
205 enum StreamType stream_type;
206 char filename[1024]; /* stream filename */
207 struct FFStream *feed; /* feed we are using (can be null if
209 AVDictionary *in_opts; /* input parameters */
210 AVInputFormat *ifmt; /* if non NULL, force input format */
213 char dynamic_acl[1024];
215 int prebuffer; /* Number of millseconds early to start */
216 int64_t max_time; /* Number of milliseconds to run */
218 AVStream *streams[MAX_STREAMS];
219 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
220 char feed_filename[1024]; /* file name of the feed storage, or
221 input file name for a stream */
226 pid_t pid; /* Of ffmpeg process */
227 time_t pid_start; /* Of ffmpeg process */
229 struct FFStream *next;
230 unsigned bandwidth; /* bandwidth, in kbits/s */
233 /* multicast specific */
235 struct in_addr multicast_ip;
236 int multicast_port; /* first port used for multicast */
238 int loop; /* if true, send the stream in loops (only meaningful if file) */
241 int feed_opened; /* true if someone is writing to the feed */
242 int is_feed; /* true if it is a feed */
243 int readonly; /* True if writing is prohibited to the file */
244 int truncate; /* True if feeder connection truncate the feed file */
246 int64_t bytes_served;
247 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
248 int64_t feed_write_index; /* current write position in feed (it wraps around) */
249 int64_t feed_size; /* current size of feed */
250 struct FFStream *next_feed;
253 typedef struct FeedData {
254 long long data_count;
255 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
258 static struct sockaddr_in my_http_addr;
259 static struct sockaddr_in my_rtsp_addr;
261 static char logfilename[1024];
262 static HTTPContext *first_http_ctx;
263 static FFStream *first_feed; /* contains only feeds */
264 static FFStream *first_stream; /* contains all streams, including feeds */
266 static void new_connection(int server_fd, int is_rtsp);
267 static void close_connection(HTTPContext *c);
270 static int handle_connection(HTTPContext *c);
271 static int http_parse_request(HTTPContext *c);
272 static int http_send_data(HTTPContext *c);
273 static void compute_status(HTTPContext *c);
274 static int open_input_stream(HTTPContext *c, const char *info);
275 static int http_start_receive_data(HTTPContext *c);
276 static int http_receive_data(HTTPContext *c);
279 static int rtsp_parse_request(HTTPContext *c);
280 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
281 static void rtsp_cmd_options(HTTPContext *c, const char *url);
282 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
283 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
284 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
285 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
288 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
289 struct in_addr my_ip);
292 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
293 FFStream *stream, const char *session_id,
294 enum RTSPLowerTransport rtp_protocol);
295 static int rtp_new_av_stream(HTTPContext *c,
296 int stream_index, struct sockaddr_in *dest_addr,
297 HTTPContext *rtsp_c);
299 static const char *my_program_name;
300 static const char *my_program_dir;
302 static const char *config_filename = "/etc/ffserver.conf";
304 static int ffserver_debug;
305 static int ffserver_daemon;
306 static int no_launch;
307 static int need_to_start_children;
309 /* maximum number of simultaneous HTTP connections */
310 static unsigned int nb_max_http_connections = 2000;
311 static unsigned int nb_max_connections = 5;
312 static unsigned int nb_connections;
314 static uint64_t max_bandwidth = 1000;
315 static uint64_t current_bandwidth;
317 static int64_t cur_time; // Making this global saves on passing it around everywhere
319 static AVLFG random_state;
321 static FILE *logfile = NULL;
323 /* FIXME: make ffserver work with IPv6 */
324 void exit_program(int ret)
329 /* resolve host with also IP address parsing */
330 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
333 if (!ff_inet_aton(hostname, sin_addr)) {
335 struct addrinfo *ai, *cur;
336 struct addrinfo hints;
337 memset(&hints, 0, sizeof(hints));
338 hints.ai_family = AF_INET;
339 if (getaddrinfo(hostname, NULL, &hints, &ai))
341 /* getaddrinfo returns a linked list of addrinfo structs.
342 * Even if we set ai_family = AF_INET above, make sure
343 * that the returned one actually is of the correct type. */
344 for (cur = ai; cur; cur = cur->ai_next) {
345 if (cur->ai_family == AF_INET) {
346 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
355 hp = gethostbyname(hostname);
358 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
364 static char *ctime1(char *buf2)
372 p = buf2 + strlen(p) - 1;
378 static void http_vlog(const char *fmt, va_list vargs)
380 static int print_prefix = 1;
385 fprintf(logfile, "%s ", buf);
387 print_prefix = strstr(fmt, "\n") != NULL;
388 vfprintf(logfile, fmt, vargs);
394 __attribute__ ((format (printf, 1, 2)))
396 static void http_log(const char *fmt, ...)
399 va_start(vargs, fmt);
400 http_vlog(fmt, vargs);
404 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
406 static int print_prefix = 1;
407 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
408 if (level > av_log_get_level())
410 if (print_prefix && avc)
411 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
412 print_prefix = strstr(fmt, "\n") != NULL;
413 http_vlog(fmt, vargs);
416 static void log_connection(HTTPContext *c)
421 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
422 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
423 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
426 static void update_datarate(DataRateData *drd, int64_t count)
428 if (!drd->time1 && !drd->count1) {
429 drd->time1 = drd->time2 = cur_time;
430 drd->count1 = drd->count2 = count;
431 } else if (cur_time - drd->time2 > 5000) {
432 drd->time1 = drd->time2;
433 drd->count1 = drd->count2;
434 drd->time2 = cur_time;
439 /* In bytes per second */
440 static int compute_datarate(DataRateData *drd, int64_t count)
442 if (cur_time == drd->time1)
445 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
449 static void start_children(FFStream *feed)
454 for (; feed; feed = feed->next) {
455 if (feed->child_argv && !feed->pid) {
456 feed->pid_start = time(0);
461 http_log("Unable to create children\n");
470 av_strlcpy(pathname, my_program_name, sizeof(pathname));
472 slash = strrchr(pathname, '/');
477 strcpy(slash, "ffmpeg");
479 http_log("Launch commandline: ");
480 http_log("%s ", pathname);
481 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
482 http_log("%s ", feed->child_argv[i]);
485 for (i = 3; i < 256; i++)
488 if (!ffserver_debug) {
489 i = open("/dev/null", O_RDWR);
498 /* This is needed to make relative pathnames work */
499 chdir(my_program_dir);
501 signal(SIGPIPE, SIG_DFL);
503 execvp(pathname, feed->child_argv);
511 /* open a listening socket */
512 static int socket_open_listen(struct sockaddr_in *my_addr)
516 server_fd = socket(AF_INET,SOCK_STREAM,0);
523 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
525 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
527 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
529 closesocket(server_fd);
533 if (listen (server_fd, 5) < 0) {
535 closesocket(server_fd);
538 ff_socket_nonblock(server_fd, 1);
543 /* start all multicast streams */
544 static void start_multicast(void)
549 struct sockaddr_in dest_addr;
550 int default_port, stream_index;
553 for(stream = first_stream; stream != NULL; stream = stream->next) {
554 if (stream->is_multicast) {
555 /* open the RTP connection */
556 snprintf(session_id, sizeof(session_id), "%08x%08x",
557 av_lfg_get(&random_state), av_lfg_get(&random_state));
559 /* choose a port if none given */
560 if (stream->multicast_port == 0) {
561 stream->multicast_port = default_port;
565 dest_addr.sin_family = AF_INET;
566 dest_addr.sin_addr = stream->multicast_ip;
567 dest_addr.sin_port = htons(stream->multicast_port);
569 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
570 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
574 if (open_input_stream(rtp_c, "") < 0) {
575 http_log("Could not open input stream for stream '%s'\n",
580 /* open each RTP stream */
581 for(stream_index = 0; stream_index < stream->nb_streams;
583 dest_addr.sin_port = htons(stream->multicast_port +
585 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
586 http_log("Could not open output stream '%s/streamid=%d'\n",
587 stream->filename, stream_index);
592 /* change state to send data */
593 rtp_c->state = HTTPSTATE_SEND_DATA;
598 /* main loop of the http server */
599 static int http_server(void)
601 int server_fd = 0, rtsp_server_fd = 0;
602 int ret, delay, delay1;
603 struct pollfd *poll_table, *poll_entry;
604 HTTPContext *c, *c_next;
606 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
607 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
611 if (my_http_addr.sin_port) {
612 server_fd = socket_open_listen(&my_http_addr);
617 if (my_rtsp_addr.sin_port) {
618 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
619 if (rtsp_server_fd < 0)
623 if (!rtsp_server_fd && !server_fd) {
624 http_log("HTTP and RTSP disabled.\n");
628 http_log("FFserver started.\n");
630 start_children(first_feed);
635 poll_entry = poll_table;
637 poll_entry->fd = server_fd;
638 poll_entry->events = POLLIN;
641 if (rtsp_server_fd) {
642 poll_entry->fd = rtsp_server_fd;
643 poll_entry->events = POLLIN;
647 /* wait for events on each HTTP handle */
654 case HTTPSTATE_SEND_HEADER:
655 case RTSPSTATE_SEND_REPLY:
656 case RTSPSTATE_SEND_PACKET:
657 c->poll_entry = poll_entry;
659 poll_entry->events = POLLOUT;
662 case HTTPSTATE_SEND_DATA_HEADER:
663 case HTTPSTATE_SEND_DATA:
664 case HTTPSTATE_SEND_DATA_TRAILER:
665 if (!c->is_packetized) {
666 /* for TCP, we output as much as we can (may need to put a limit) */
667 c->poll_entry = poll_entry;
669 poll_entry->events = POLLOUT;
672 /* when ffserver is doing the timing, we work by
673 looking at which packet need to be sent every
675 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
680 case HTTPSTATE_WAIT_REQUEST:
681 case HTTPSTATE_RECEIVE_DATA:
682 case HTTPSTATE_WAIT_FEED:
683 case RTSPSTATE_WAIT_REQUEST:
684 /* need to catch errors */
685 c->poll_entry = poll_entry;
687 poll_entry->events = POLLIN;/* Maybe this will work */
691 c->poll_entry = NULL;
697 /* wait for an event on one connection. We poll at least every
698 second to handle timeouts */
700 ret = poll(poll_table, poll_entry - poll_table, delay);
701 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
702 ff_neterrno() != AVERROR(EINTR))
706 cur_time = av_gettime() / 1000;
708 if (need_to_start_children) {
709 need_to_start_children = 0;
710 start_children(first_feed);
713 /* now handle the events */
714 for(c = first_http_ctx; c != NULL; c = c_next) {
716 if (handle_connection(c) < 0) {
717 /* close and free the connection */
723 poll_entry = poll_table;
725 /* new HTTP connection request ? */
726 if (poll_entry->revents & POLLIN)
727 new_connection(server_fd, 0);
730 if (rtsp_server_fd) {
731 /* new RTSP connection request ? */
732 if (poll_entry->revents & POLLIN)
733 new_connection(rtsp_server_fd, 1);
738 /* start waiting for a new HTTP/RTSP request */
739 static void start_wait_request(HTTPContext *c, int is_rtsp)
741 c->buffer_ptr = c->buffer;
742 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
745 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
746 c->state = RTSPSTATE_WAIT_REQUEST;
748 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
749 c->state = HTTPSTATE_WAIT_REQUEST;
753 static void http_send_too_busy_reply(int fd)
756 int len = snprintf(buffer, sizeof(buffer),
757 "HTTP/1.0 503 Server too busy\r\n"
758 "Content-type: text/html\r\n"
760 "<html><head><title>Too busy</title></head><body>\r\n"
761 "<p>The server is too busy to serve your request at this time.</p>\r\n"
762 "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
763 "</body></html>\r\n",
764 nb_connections, nb_max_connections);
765 send(fd, buffer, len, 0);
769 static void new_connection(int server_fd, int is_rtsp)
771 struct sockaddr_in from_addr;
773 HTTPContext *c = NULL;
775 len = sizeof(from_addr);
776 fd = accept(server_fd, (struct sockaddr *)&from_addr,
779 http_log("error during accept %s\n", strerror(errno));
782 ff_socket_nonblock(fd, 1);
784 if (nb_connections >= nb_max_connections) {
785 http_send_too_busy_reply(fd);
789 /* add a new connection */
790 c = av_mallocz(sizeof(HTTPContext));
795 c->poll_entry = NULL;
796 c->from_addr = from_addr;
797 c->buffer_size = IOBUFFER_INIT_SIZE;
798 c->buffer = av_malloc(c->buffer_size);
802 c->next = first_http_ctx;
806 start_wait_request(c, is_rtsp);
818 static void close_connection(HTTPContext *c)
820 HTTPContext **cp, *c1;
822 AVFormatContext *ctx;
826 /* remove connection from list */
827 cp = &first_http_ctx;
828 while ((*cp) != NULL) {
836 /* remove references, if any (XXX: do it faster) */
837 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
842 /* remove connection associated resources */
846 /* close each frame parser */
847 for(i=0;i<c->fmt_in->nb_streams;i++) {
848 st = c->fmt_in->streams[i];
849 if (st->codec->codec)
850 avcodec_close(st->codec);
852 av_close_input_file(c->fmt_in);
855 /* free RTP output streams if any */
858 nb_streams = c->stream->nb_streams;
860 for(i=0;i<nb_streams;i++) {
863 av_write_trailer(ctx);
864 av_dict_free(&ctx->metadata);
865 av_free(ctx->streams[0]);
868 h = c->rtp_handles[i];
875 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
878 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
879 av_write_trailer(ctx);
880 av_freep(&c->pb_buffer);
881 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
886 for(i=0; i<ctx->nb_streams; i++)
887 av_free(ctx->streams[i]);
889 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
890 current_bandwidth -= c->stream->bandwidth;
892 /* signal that there is no feed if we are the feeder socket */
893 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
894 c->stream->feed_opened = 0;
898 av_freep(&c->pb_buffer);
899 av_freep(&c->packet_buffer);
905 static int handle_connection(HTTPContext *c)
910 case HTTPSTATE_WAIT_REQUEST:
911 case RTSPSTATE_WAIT_REQUEST:
913 if ((c->timeout - cur_time) < 0)
915 if (c->poll_entry->revents & (POLLERR | POLLHUP))
918 /* no need to read if no events */
919 if (!(c->poll_entry->revents & POLLIN))
923 len = recv(c->fd, c->buffer_ptr, 1, 0);
925 if (ff_neterrno() != AVERROR(EAGAIN) &&
926 ff_neterrno() != AVERROR(EINTR))
928 } else if (len == 0) {
931 /* search for end of request. */
933 c->buffer_ptr += len;
935 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
936 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
937 /* request found : parse it and reply */
938 if (c->state == HTTPSTATE_WAIT_REQUEST) {
939 ret = http_parse_request(c);
941 ret = rtsp_parse_request(c);
945 } else if (ptr >= c->buffer_end) {
946 /* request too long: cannot do anything */
948 } else goto read_loop;
952 case HTTPSTATE_SEND_HEADER:
953 if (c->poll_entry->revents & (POLLERR | POLLHUP))
956 /* no need to write if no events */
957 if (!(c->poll_entry->revents & POLLOUT))
959 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
961 if (ff_neterrno() != AVERROR(EAGAIN) &&
962 ff_neterrno() != AVERROR(EINTR)) {
963 /* error : close connection */
964 av_freep(&c->pb_buffer);
968 c->buffer_ptr += len;
970 c->stream->bytes_served += len;
971 c->data_count += len;
972 if (c->buffer_ptr >= c->buffer_end) {
973 av_freep(&c->pb_buffer);
977 /* all the buffer was sent : synchronize to the incoming stream */
978 c->state = HTTPSTATE_SEND_DATA_HEADER;
979 c->buffer_ptr = c->buffer_end = c->buffer;
984 case HTTPSTATE_SEND_DATA:
985 case HTTPSTATE_SEND_DATA_HEADER:
986 case HTTPSTATE_SEND_DATA_TRAILER:
987 /* for packetized output, we consider we can always write (the
988 input streams sets the speed). It may be better to verify
989 that we do not rely too much on the kernel queues */
990 if (!c->is_packetized) {
991 if (c->poll_entry->revents & (POLLERR | POLLHUP))
994 /* no need to read if no events */
995 if (!(c->poll_entry->revents & POLLOUT))
998 if (http_send_data(c) < 0)
1000 /* close connection if trailer sent */
1001 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1004 case HTTPSTATE_RECEIVE_DATA:
1005 /* no need to read if no events */
1006 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1008 if (!(c->poll_entry->revents & POLLIN))
1010 if (http_receive_data(c) < 0)
1013 case HTTPSTATE_WAIT_FEED:
1014 /* no need to read if no events */
1015 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1018 /* nothing to do, we'll be waken up by incoming feed packets */
1021 case RTSPSTATE_SEND_REPLY:
1022 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1023 av_freep(&c->pb_buffer);
1026 /* no need to write if no events */
1027 if (!(c->poll_entry->revents & POLLOUT))
1029 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1031 if (ff_neterrno() != AVERROR(EAGAIN) &&
1032 ff_neterrno() != AVERROR(EINTR)) {
1033 /* error : close connection */
1034 av_freep(&c->pb_buffer);
1038 c->buffer_ptr += len;
1039 c->data_count += len;
1040 if (c->buffer_ptr >= c->buffer_end) {
1041 /* all the buffer was sent : wait for a new request */
1042 av_freep(&c->pb_buffer);
1043 start_wait_request(c, 1);
1047 case RTSPSTATE_SEND_PACKET:
1048 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1049 av_freep(&c->packet_buffer);
1052 /* no need to write if no events */
1053 if (!(c->poll_entry->revents & POLLOUT))
1055 len = send(c->fd, c->packet_buffer_ptr,
1056 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1058 if (ff_neterrno() != AVERROR(EAGAIN) &&
1059 ff_neterrno() != AVERROR(EINTR)) {
1060 /* error : close connection */
1061 av_freep(&c->packet_buffer);
1065 c->packet_buffer_ptr += len;
1066 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1067 /* all the buffer was sent : wait for a new request */
1068 av_freep(&c->packet_buffer);
1069 c->state = RTSPSTATE_WAIT_REQUEST;
1073 case HTTPSTATE_READY:
1082 static int extract_rates(char *rates, int ratelen, const char *request)
1086 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1087 if (strncasecmp(p, "Pragma:", 7) == 0) {
1088 const char *q = p + 7;
1090 while (*q && *q != '\n' && isspace(*q))
1093 if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1099 memset(rates, 0xff, ratelen);
1102 while (*q && *q != '\n' && *q != ':')
1105 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1109 if (stream_no < ratelen && stream_no >= 0)
1110 rates[stream_no] = rate_no;
1112 while (*q && *q != '\n' && !isspace(*q))
1119 p = strchr(p, '\n');
1129 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1132 int best_bitrate = 100000000;
1135 for (i = 0; i < feed->nb_streams; i++) {
1136 AVCodecContext *feed_codec = feed->streams[i]->codec;
1138 if (feed_codec->codec_id != codec->codec_id ||
1139 feed_codec->sample_rate != codec->sample_rate ||
1140 feed_codec->width != codec->width ||
1141 feed_codec->height != codec->height)
1144 /* Potential stream */
1146 /* We want the fastest stream less than bit_rate, or the slowest
1147 * faster than bit_rate
1150 if (feed_codec->bit_rate <= bit_rate) {
1151 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1152 best_bitrate = feed_codec->bit_rate;
1156 if (feed_codec->bit_rate < best_bitrate) {
1157 best_bitrate = feed_codec->bit_rate;
1166 static int modify_current_stream(HTTPContext *c, char *rates)
1169 FFStream *req = c->stream;
1170 int action_required = 0;
1172 /* Not much we can do for a feed */
1176 for (i = 0; i < req->nb_streams; i++) {
1177 AVCodecContext *codec = req->streams[i]->codec;
1181 c->switch_feed_streams[i] = req->feed_streams[i];
1184 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1187 /* Wants off or slow */
1188 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1190 /* This doesn't work well when it turns off the only stream! */
1191 c->switch_feed_streams[i] = -2;
1192 c->feed_streams[i] = -2;
1197 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1198 action_required = 1;
1201 return action_required;
1204 /* XXX: factorize in utils.c ? */
1205 /* XXX: take care with different space meaning */
1206 static void skip_spaces(const char **pp)
1210 while (*p == ' ' || *p == '\t')
1215 static void get_word(char *buf, int buf_size, const char **pp)
1223 while (!isspace(*p) && *p != '\0') {
1224 if ((q - buf) < buf_size - 1)
1233 static void get_arg(char *buf, int buf_size, const char **pp)
1240 while (isspace(*p)) p++;
1243 if (*p == '\"' || *p == '\'')
1255 if ((q - buf) < buf_size - 1)
1260 if (quote && *p == quote)
1265 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1266 const char *p, const char *filename, int line_num)
1272 get_arg(arg, sizeof(arg), &p);
1273 if (strcasecmp(arg, "allow") == 0)
1274 acl.action = IP_ALLOW;
1275 else if (strcasecmp(arg, "deny") == 0)
1276 acl.action = IP_DENY;
1278 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1279 filename, line_num, arg);
1283 get_arg(arg, sizeof(arg), &p);
1285 if (resolve_host(&acl.first, arg) != 0) {
1286 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1287 filename, line_num, arg);
1290 acl.last = acl.first;
1292 get_arg(arg, sizeof(arg), &p);
1295 if (resolve_host(&acl.last, arg) != 0) {
1296 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1297 filename, line_num, arg);
1303 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1304 IPAddressACL **naclp = 0;
1310 naclp = &stream->acl;
1316 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1317 filename, line_num);
1323 naclp = &(*naclp)->next;
1331 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1336 IPAddressACL *acl = NULL;
1340 f = fopen(stream->dynamic_acl, "r");
1342 perror(stream->dynamic_acl);
1346 acl = av_mallocz(sizeof(IPAddressACL));
1350 if (fgets(line, sizeof(line), f) == NULL)
1356 if (*p == '\0' || *p == '#')
1358 get_arg(cmd, sizeof(cmd), &p);
1360 if (!strcasecmp(cmd, "ACL"))
1361 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1368 static void free_acl_list(IPAddressACL *in_acl)
1370 IPAddressACL *pacl,*pacl2;
1380 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1382 enum IPAddressAction last_action = IP_DENY;
1384 struct in_addr *src = &c->from_addr.sin_addr;
1385 unsigned long src_addr = src->s_addr;
1387 for (acl = in_acl; acl; acl = acl->next) {
1388 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1389 return (acl->action == IP_ALLOW) ? 1 : 0;
1390 last_action = acl->action;
1393 /* Nothing matched, so return not the last action */
1394 return (last_action == IP_DENY) ? 1 : 0;
1397 static int validate_acl(FFStream *stream, HTTPContext *c)
1403 /* if stream->acl is null validate_acl_list will return 1 */
1404 ret = validate_acl_list(stream->acl, c);
1406 if (stream->dynamic_acl[0]) {
1407 acl = parse_dynamic_acl(stream, c);
1409 ret = validate_acl_list(acl, c);
1417 /* compute the real filename of a file by matching it without its
1418 extensions to all the stream filenames */
1419 static void compute_real_filename(char *filename, int max_size)
1426 /* compute filename by matching without the file extensions */
1427 av_strlcpy(file1, filename, sizeof(file1));
1428 p = strrchr(file1, '.');
1431 for(stream = first_stream; stream != NULL; stream = stream->next) {
1432 av_strlcpy(file2, stream->filename, sizeof(file2));
1433 p = strrchr(file2, '.');
1436 if (!strcmp(file1, file2)) {
1437 av_strlcpy(filename, stream->filename, max_size);
1452 /* parse http request and prepare header */
1453 static int http_parse_request(HTTPContext *c)
1456 enum RedirType redir_type;
1458 char info[1024], filename[1024];
1462 const char *mime_type;
1466 char *useragent = 0;
1469 get_word(cmd, sizeof(cmd), (const char **)&p);
1470 av_strlcpy(c->method, cmd, sizeof(c->method));
1472 if (!strcmp(cmd, "GET"))
1474 else if (!strcmp(cmd, "POST"))
1479 get_word(url, sizeof(url), (const char **)&p);
1480 av_strlcpy(c->url, url, sizeof(c->url));
1482 get_word(protocol, sizeof(protocol), (const char **)&p);
1483 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1486 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1489 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1491 /* find the filename and the optional info string in the request */
1492 p = strchr(url, '?');
1494 av_strlcpy(info, p, sizeof(info));
1499 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1501 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1502 if (strncasecmp(p, "User-Agent:", 11) == 0) {
1504 if (*useragent && *useragent != '\n' && isspace(*useragent))
1508 p = strchr(p, '\n');
1515 redir_type = REDIR_NONE;
1516 if (av_match_ext(filename, "asx")) {
1517 redir_type = REDIR_ASX;
1518 filename[strlen(filename)-1] = 'f';
1519 } else if (av_match_ext(filename, "asf") &&
1520 (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1521 /* if this isn't WMP or lookalike, return the redirector file */
1522 redir_type = REDIR_ASF;
1523 } else if (av_match_ext(filename, "rpm,ram")) {
1524 redir_type = REDIR_RAM;
1525 strcpy(filename + strlen(filename)-2, "m");
1526 } else if (av_match_ext(filename, "rtsp")) {
1527 redir_type = REDIR_RTSP;
1528 compute_real_filename(filename, sizeof(filename) - 1);
1529 } else if (av_match_ext(filename, "sdp")) {
1530 redir_type = REDIR_SDP;
1531 compute_real_filename(filename, sizeof(filename) - 1);
1534 // "redirect" / request to index.html
1535 if (!strlen(filename))
1536 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1538 stream = first_stream;
1539 while (stream != NULL) {
1540 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1542 stream = stream->next;
1544 if (stream == NULL) {
1545 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1546 http_log("File '%s' not found\n", url);
1551 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1552 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1554 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1555 c->http_error = 301;
1557 q += snprintf(q, c->buffer_size,
1558 "HTTP/1.0 301 Moved\r\n"
1560 "Content-type: text/html\r\n"
1562 "<html><head><title>Moved</title></head><body>\r\n"
1563 "You should be <a href=\"%s\">redirected</a>.\r\n"
1564 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1565 /* prepare output buffer */
1566 c->buffer_ptr = c->buffer;
1568 c->state = HTTPSTATE_SEND_HEADER;
1572 /* If this is WMP, get the rate information */
1573 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1574 if (modify_current_stream(c, ratebuf)) {
1575 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1576 if (c->switch_feed_streams[i] >= 0)
1577 c->switch_feed_streams[i] = -1;
1582 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1583 current_bandwidth += stream->bandwidth;
1585 /* If already streaming this feed, do not let start another feeder. */
1586 if (stream->feed_opened) {
1587 snprintf(msg, sizeof(msg), "This feed is already being received.");
1588 http_log("Feed '%s' already being received\n", stream->feed_filename);
1592 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1593 c->http_error = 503;
1595 q += snprintf(q, c->buffer_size,
1596 "HTTP/1.0 503 Server too busy\r\n"
1597 "Content-type: text/html\r\n"
1599 "<html><head><title>Too busy</title></head><body>\r\n"
1600 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1601 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1602 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1603 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1604 /* prepare output buffer */
1605 c->buffer_ptr = c->buffer;
1607 c->state = HTTPSTATE_SEND_HEADER;
1611 if (redir_type != REDIR_NONE) {
1614 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1615 if (strncasecmp(p, "Host:", 5) == 0) {
1619 p = strchr(p, '\n');
1630 while (isspace(*hostinfo))
1633 eoh = strchr(hostinfo, '\n');
1635 if (eoh[-1] == '\r')
1638 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1639 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1640 hostbuf[eoh - hostinfo] = 0;
1642 c->http_error = 200;
1644 switch(redir_type) {
1646 q += snprintf(q, c->buffer_size,
1647 "HTTP/1.0 200 ASX Follows\r\n"
1648 "Content-type: video/x-ms-asf\r\n"
1650 "<ASX Version=\"3\">\r\n"
1651 //"<!-- Autogenerated by ffserver -->\r\n"
1652 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1653 "</ASX>\r\n", hostbuf, filename, info);
1656 q += snprintf(q, c->buffer_size,
1657 "HTTP/1.0 200 RAM Follows\r\n"
1658 "Content-type: audio/x-pn-realaudio\r\n"
1660 "# Autogenerated by ffserver\r\n"
1661 "http://%s/%s%s\r\n", hostbuf, filename, info);
1664 q += snprintf(q, c->buffer_size,
1665 "HTTP/1.0 200 ASF Redirect follows\r\n"
1666 "Content-type: video/x-ms-asf\r\n"
1669 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1673 char hostname[256], *p;
1674 /* extract only hostname */
1675 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1676 p = strrchr(hostname, ':');
1679 q += snprintf(q, c->buffer_size,
1680 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1681 /* XXX: incorrect mime type ? */
1682 "Content-type: application/x-rtsp\r\n"
1684 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1690 int sdp_data_size, len;
1691 struct sockaddr_in my_addr;
1693 q += snprintf(q, c->buffer_size,
1694 "HTTP/1.0 200 OK\r\n"
1695 "Content-type: application/sdp\r\n"
1698 len = sizeof(my_addr);
1699 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1701 /* XXX: should use a dynamic buffer */
1702 sdp_data_size = prepare_sdp_description(stream,
1705 if (sdp_data_size > 0) {
1706 memcpy(q, sdp_data, sdp_data_size);
1718 /* prepare output buffer */
1719 c->buffer_ptr = c->buffer;
1721 c->state = HTTPSTATE_SEND_HEADER;
1727 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1731 stream->conns_served++;
1733 /* XXX: add there authenticate and IP match */
1736 /* if post, it means a feed is being sent */
1737 if (!stream->is_feed) {
1738 /* However it might be a status report from WMP! Let us log the
1739 * data as it might come in handy one day. */
1743 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1744 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1748 if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1749 client_id = strtol(p + 18, 0, 10);
1750 p = strchr(p, '\n');
1758 char *eol = strchr(logline, '\n');
1763 if (eol[-1] == '\r')
1765 http_log("%.*s\n", (int) (eol - logline), logline);
1766 c->suppress_log = 1;
1771 http_log("\nGot request:\n%s\n", c->buffer);
1774 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1777 /* Now we have to find the client_id */
1778 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1779 if (wmpc->wmp_client_id == client_id)
1783 if (wmpc && modify_current_stream(wmpc, ratebuf))
1784 wmpc->switch_pending = 1;
1787 snprintf(msg, sizeof(msg), "POST command not handled");
1791 if (http_start_receive_data(c) < 0) {
1792 snprintf(msg, sizeof(msg), "could not open feed");
1796 c->state = HTTPSTATE_RECEIVE_DATA;
1801 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1802 http_log("\nGot request:\n%s\n", c->buffer);
1805 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1808 /* open input stream */
1809 if (open_input_stream(c, info) < 0) {
1810 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1814 /* prepare http header */
1816 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1817 mime_type = c->stream->fmt->mime_type;
1819 mime_type = "application/x-octet-stream";
1820 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1822 /* for asf, we need extra headers */
1823 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1824 /* Need to allocate a client id */
1826 c->wmp_client_id = av_lfg_get(&random_state);
1828 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);
1830 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1831 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1833 /* prepare output buffer */
1835 c->buffer_ptr = c->buffer;
1837 c->state = HTTPSTATE_SEND_HEADER;
1840 c->http_error = 404;
1842 q += snprintf(q, c->buffer_size,
1843 "HTTP/1.0 404 Not Found\r\n"
1844 "Content-type: text/html\r\n"
1847 "<head><title>404 Not Found</title></head>\n"
1850 /* prepare output buffer */
1851 c->buffer_ptr = c->buffer;
1853 c->state = HTTPSTATE_SEND_HEADER;
1857 c->http_error = 200; /* horrible : we use this value to avoid
1858 going to the send data state */
1859 c->state = HTTPSTATE_SEND_HEADER;
1863 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1865 static const char *suffix = " kMGTP";
1868 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1870 avio_printf(pb, "%"PRId64"%c", count, *s);
1873 static void compute_status(HTTPContext *c)
1882 if (avio_open_dyn_buf(&pb) < 0) {
1883 /* XXX: return an error ? */
1884 c->buffer_ptr = c->buffer;
1885 c->buffer_end = c->buffer;
1889 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1890 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1891 avio_printf(pb, "Pragma: no-cache\r\n");
1892 avio_printf(pb, "\r\n");
1894 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1895 if (c->stream->feed_filename[0])
1896 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1897 avio_printf(pb, "</head>\n<body>");
1898 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1900 avio_printf(pb, "<h2>Available Streams</h2>\n");
1901 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1902 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");
1903 stream = first_stream;
1904 while (stream != NULL) {
1905 char sfilename[1024];
1908 if (stream->feed != stream) {
1909 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1910 eosf = sfilename + strlen(sfilename);
1911 if (eosf - sfilename >= 4) {
1912 if (strcmp(eosf - 4, ".asf") == 0)
1913 strcpy(eosf - 4, ".asx");
1914 else if (strcmp(eosf - 3, ".rm") == 0)
1915 strcpy(eosf - 3, ".ram");
1916 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1917 /* generate a sample RTSP director if
1918 unicast. Generate an SDP redirector if
1920 eosf = strrchr(sfilename, '.');
1922 eosf = sfilename + strlen(sfilename);
1923 if (stream->is_multicast)
1924 strcpy(eosf, ".sdp");
1926 strcpy(eosf, ".rtsp");
1930 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1931 sfilename, stream->filename);
1932 avio_printf(pb, "<td align=right> %d <td align=right> ",
1933 stream->conns_served);
1934 fmt_bytecount(pb, stream->bytes_served);
1935 switch(stream->stream_type) {
1936 case STREAM_TYPE_LIVE: {
1937 int audio_bit_rate = 0;
1938 int video_bit_rate = 0;
1939 const char *audio_codec_name = "";
1940 const char *video_codec_name = "";
1941 const char *audio_codec_name_extra = "";
1942 const char *video_codec_name_extra = "";
1944 for(i=0;i<stream->nb_streams;i++) {
1945 AVStream *st = stream->streams[i];
1946 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1947 switch(st->codec->codec_type) {
1948 case AVMEDIA_TYPE_AUDIO:
1949 audio_bit_rate += st->codec->bit_rate;
1951 if (*audio_codec_name)
1952 audio_codec_name_extra = "...";
1953 audio_codec_name = codec->name;
1956 case AVMEDIA_TYPE_VIDEO:
1957 video_bit_rate += st->codec->bit_rate;
1959 if (*video_codec_name)
1960 video_codec_name_extra = "...";
1961 video_codec_name = codec->name;
1964 case AVMEDIA_TYPE_DATA:
1965 video_bit_rate += st->codec->bit_rate;
1971 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",
1974 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1975 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1977 avio_printf(pb, "<td>%s", stream->feed->filename);
1979 avio_printf(pb, "<td>%s", stream->feed_filename);
1980 avio_printf(pb, "\n");
1984 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1988 stream = stream->next;
1990 avio_printf(pb, "</table>\n");
1992 stream = first_stream;
1993 while (stream != NULL) {
1994 if (stream->feed == stream) {
1995 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1997 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1999 #if defined(linux) && !defined(CONFIG_NOCUTILS)
2004 /* This is somewhat linux specific I guess */
2005 snprintf(ps_cmd, sizeof(ps_cmd),
2006 "ps -o \"%%cpu,cputime\" --no-headers %d",
2009 pid_stat = popen(ps_cmd, "r");
2014 if (fscanf(pid_stat, "%10s %64s", cpuperc,
2016 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2024 avio_printf(pb, "<p>");
2026 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");
2028 for (i = 0; i < stream->nb_streams; i++) {
2029 AVStream *st = stream->streams[i];
2030 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2031 const char *type = "unknown";
2032 char parameters[64];
2036 switch(st->codec->codec_type) {
2037 case AVMEDIA_TYPE_AUDIO:
2039 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2041 case AVMEDIA_TYPE_VIDEO:
2043 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2044 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2049 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2050 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2052 avio_printf(pb, "</table>\n");
2055 stream = stream->next;
2058 /* connection status */
2059 avio_printf(pb, "<h2>Connection Status</h2>\n");
2061 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2062 nb_connections, nb_max_connections);
2064 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2065 current_bandwidth, max_bandwidth);
2067 avio_printf(pb, "<table>\n");
2068 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");
2069 c1 = first_http_ctx;
2071 while (c1 != NULL) {
2077 for (j = 0; j < c1->stream->nb_streams; j++) {
2078 if (!c1->stream->feed)
2079 bitrate += c1->stream->streams[j]->codec->bit_rate;
2080 else if (c1->feed_streams[j] >= 0)
2081 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2086 p = inet_ntoa(c1->from_addr.sin_addr);
2087 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2089 c1->stream ? c1->stream->filename : "",
2090 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2093 http_state[c1->state]);
2094 fmt_bytecount(pb, bitrate);
2095 avio_printf(pb, "<td align=right>");
2096 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2097 avio_printf(pb, "<td align=right>");
2098 fmt_bytecount(pb, c1->data_count);
2099 avio_printf(pb, "\n");
2102 avio_printf(pb, "</table>\n");
2107 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2108 avio_printf(pb, "</body>\n</html>\n");
2110 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2111 c->buffer_ptr = c->pb_buffer;
2112 c->buffer_end = c->pb_buffer + len;
2115 /* check if the parser needs to be opened for stream i */
2116 static void open_parser(AVFormatContext *s, int i)
2118 AVStream *st = s->streams[i];
2121 if (!st->codec->codec) {
2122 codec = avcodec_find_decoder(st->codec->codec_id);
2123 if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2124 st->codec->parse_only = 1;
2125 if (avcodec_open2(st->codec, codec, NULL) < 0)
2126 st->codec->parse_only = 0;
2131 static int open_input_stream(HTTPContext *c, const char *info)
2134 char input_filename[1024];
2135 AVFormatContext *s = NULL;
2139 /* find file name */
2140 if (c->stream->feed) {
2141 strcpy(input_filename, c->stream->feed->feed_filename);
2142 /* compute position (absolute time) */
2143 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2144 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2146 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2147 int prebuffer = strtol(buf, 0, 10);
2148 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2150 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2152 strcpy(input_filename, c->stream->feed_filename);
2153 /* compute position (relative time) */
2154 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2155 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2160 if (input_filename[0] == '\0')
2164 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2165 http_log("could not open %s: %d\n", input_filename, ret);
2168 s->flags |= AVFMT_FLAG_GENPTS;
2170 if (strcmp(s->iformat->name, "ffm") && avformat_find_stream_info(c->fmt_in, NULL) < 0) {
2171 http_log("Could not find stream info '%s'\n", input_filename);
2172 av_close_input_file(s);
2176 /* open each parser */
2177 for(i=0;i<s->nb_streams;i++)
2180 /* choose stream as clock source (we favorize video stream if
2181 present) for packet sending */
2182 c->pts_stream_index = 0;
2183 for(i=0;i<c->stream->nb_streams;i++) {
2184 if (c->pts_stream_index == 0 &&
2185 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2186 c->pts_stream_index = i;
2190 if (c->fmt_in->iformat->read_seek)
2191 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2192 /* set the start time (needed for maxtime and RTP packet timing) */
2193 c->start_time = cur_time;
2194 c->first_pts = AV_NOPTS_VALUE;
2198 /* return the server clock (in us) */
2199 static int64_t get_server_clock(HTTPContext *c)
2201 /* compute current pts value from system time */
2202 return (cur_time - c->start_time) * 1000;
2205 /* return the estimated time at which the current packet must be sent
2207 static int64_t get_packet_send_clock(HTTPContext *c)
2209 int bytes_left, bytes_sent, frame_bytes;
2211 frame_bytes = c->cur_frame_bytes;
2212 if (frame_bytes <= 0)
2215 bytes_left = c->buffer_end - c->buffer_ptr;
2216 bytes_sent = frame_bytes - bytes_left;
2217 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2222 static int http_prepare_data(HTTPContext *c)
2225 AVFormatContext *ctx;
2227 av_freep(&c->pb_buffer);
2229 case HTTPSTATE_SEND_DATA_HEADER:
2230 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2231 av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2232 av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2233 av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2234 av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2236 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2238 for(i=0;i<c->stream->nb_streams;i++) {
2240 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2241 /* if file or feed, then just take streams from FFStream struct */
2242 if (!c->stream->feed ||
2243 c->stream->feed == c->stream)
2244 src = c->stream->streams[i];
2246 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2248 *(c->fmt_ctx.streams[i]) = *src;
2249 c->fmt_ctx.streams[i]->priv_data = 0;
2250 c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2251 AVStream, not in codec */
2253 /* set output format parameters */
2254 c->fmt_ctx.oformat = c->stream->fmt;
2255 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2257 c->got_key_frame = 0;
2259 /* prepare header and save header data in a stream */
2260 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2261 /* XXX: potential leak */
2264 c->fmt_ctx.pb->seekable = 0;
2267 * HACK to avoid mpeg ps muxer to spit many underflow errors
2268 * Default value from FFmpeg
2269 * Try to set it use configuration option
2271 c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
2272 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2274 if (avformat_write_header(&c->fmt_ctx, NULL) < 0) {
2275 http_log("Error writing output header\n");
2278 av_dict_free(&c->fmt_ctx.metadata);
2280 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2281 c->buffer_ptr = c->pb_buffer;
2282 c->buffer_end = c->pb_buffer + len;
2284 c->state = HTTPSTATE_SEND_DATA;
2285 c->last_packet_sent = 0;
2287 case HTTPSTATE_SEND_DATA:
2288 /* find a new packet */
2289 /* read a packet from the input stream */
2290 if (c->stream->feed)
2291 ffm_set_write_index(c->fmt_in,
2292 c->stream->feed->feed_write_index,
2293 c->stream->feed->feed_size);
2295 if (c->stream->max_time &&
2296 c->stream->max_time + c->start_time - cur_time < 0)
2297 /* We have timed out */
2298 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2302 ret = av_read_frame(c->fmt_in, &pkt);
2304 if (c->stream->feed) {
2305 /* if coming from feed, it means we reached the end of the
2306 ffm file, so must wait for more data */
2307 c->state = HTTPSTATE_WAIT_FEED;
2308 return 1; /* state changed */
2309 } else if (ret == AVERROR(EAGAIN)) {
2310 /* input not ready, come back later */
2313 if (c->stream->loop) {
2314 av_close_input_file(c->fmt_in);
2316 if (open_input_stream(c, "") < 0)
2321 /* must send trailer now because eof or error */
2322 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2326 int source_index = pkt.stream_index;
2327 /* update first pts if needed */
2328 if (c->first_pts == AV_NOPTS_VALUE) {
2329 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2330 c->start_time = cur_time;
2332 /* send it to the appropriate stream */
2333 if (c->stream->feed) {
2334 /* if coming from a feed, select the right stream */
2335 if (c->switch_pending) {
2336 c->switch_pending = 0;
2337 for(i=0;i<c->stream->nb_streams;i++) {
2338 if (c->switch_feed_streams[i] == pkt.stream_index)
2339 if (pkt.flags & AV_PKT_FLAG_KEY)
2340 c->switch_feed_streams[i] = -1;
2341 if (c->switch_feed_streams[i] >= 0)
2342 c->switch_pending = 1;
2345 for(i=0;i<c->stream->nb_streams;i++) {
2346 if (c->stream->feed_streams[i] == pkt.stream_index) {
2347 AVStream *st = c->fmt_in->streams[source_index];
2348 pkt.stream_index = i;
2349 if (pkt.flags & AV_PKT_FLAG_KEY &&
2350 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2351 c->stream->nb_streams == 1))
2352 c->got_key_frame = 1;
2353 if (!c->stream->send_on_key || c->got_key_frame)
2358 AVCodecContext *codec;
2359 AVStream *ist, *ost;
2361 ist = c->fmt_in->streams[source_index];
2362 /* specific handling for RTP: we use several
2363 output stream (one for each RTP
2364 connection). XXX: need more abstract handling */
2365 if (c->is_packetized) {
2366 /* compute send time and duration */
2367 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2368 c->cur_pts -= c->first_pts;
2369 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2370 /* find RTP context */
2371 c->packet_stream_index = pkt.stream_index;
2372 ctx = c->rtp_ctx[c->packet_stream_index];
2374 av_free_packet(&pkt);
2377 codec = ctx->streams[0]->codec;
2378 /* only one stream per RTP connection */
2379 pkt.stream_index = 0;
2383 codec = ctx->streams[pkt.stream_index]->codec;
2386 if (c->is_packetized) {
2387 int max_packet_size;
2388 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2389 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2391 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2392 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2394 ret = avio_open_dyn_buf(&ctx->pb);
2397 /* XXX: potential leak */
2400 ost = ctx->streams[pkt.stream_index];
2402 ctx->pb->seekable = 0;
2403 if (pkt.dts != AV_NOPTS_VALUE)
2404 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2405 if (pkt.pts != AV_NOPTS_VALUE)
2406 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2407 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2408 if (av_write_frame(ctx, &pkt) < 0) {
2409 http_log("Error writing frame to output\n");
2410 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2413 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2414 c->cur_frame_bytes = len;
2415 c->buffer_ptr = c->pb_buffer;
2416 c->buffer_end = c->pb_buffer + len;
2418 codec->frame_number++;
2420 av_free_packet(&pkt);
2424 av_free_packet(&pkt);
2429 case HTTPSTATE_SEND_DATA_TRAILER:
2430 /* last packet test ? */
2431 if (c->last_packet_sent || c->is_packetized)
2434 /* prepare header */
2435 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2436 /* XXX: potential leak */
2439 c->fmt_ctx.pb->seekable = 0;
2440 av_write_trailer(ctx);
2441 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2442 c->buffer_ptr = c->pb_buffer;
2443 c->buffer_end = c->pb_buffer + len;
2445 c->last_packet_sent = 1;
2451 /* should convert the format at the same time */
2452 /* send data starting at c->buffer_ptr to the output connection
2453 (either UDP or TCP connection) */
2454 static int http_send_data(HTTPContext *c)
2459 if (c->buffer_ptr >= c->buffer_end) {
2460 ret = http_prepare_data(c);
2464 /* state change requested */
2467 if (c->is_packetized) {
2468 /* RTP data output */
2469 len = c->buffer_end - c->buffer_ptr;
2471 /* fail safe - should never happen */
2473 c->buffer_ptr = c->buffer_end;
2476 len = (c->buffer_ptr[0] << 24) |
2477 (c->buffer_ptr[1] << 16) |
2478 (c->buffer_ptr[2] << 8) |
2480 if (len > (c->buffer_end - c->buffer_ptr))
2482 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2483 /* nothing to send yet: we can wait */
2487 c->data_count += len;
2488 update_datarate(&c->datarate, c->data_count);
2490 c->stream->bytes_served += len;
2492 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2493 /* RTP packets are sent inside the RTSP TCP connection */
2495 int interleaved_index, size;
2497 HTTPContext *rtsp_c;
2500 /* if no RTSP connection left, error */
2503 /* if already sending something, then wait. */
2504 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2506 if (avio_open_dyn_buf(&pb) < 0)
2508 interleaved_index = c->packet_stream_index * 2;
2509 /* RTCP packets are sent at odd indexes */
2510 if (c->buffer_ptr[1] == 200)
2511 interleaved_index++;
2512 /* write RTSP TCP header */
2514 header[1] = interleaved_index;
2515 header[2] = len >> 8;
2517 avio_write(pb, header, 4);
2518 /* write RTP packet data */
2520 avio_write(pb, c->buffer_ptr, len);
2521 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2522 /* prepare asynchronous TCP sending */
2523 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2524 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2525 c->buffer_ptr += len;
2527 /* send everything we can NOW */
2528 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2529 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2531 rtsp_c->packet_buffer_ptr += len;
2532 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2533 /* if we could not send all the data, we will
2534 send it later, so a new state is needed to
2535 "lock" the RTSP TCP connection */
2536 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2539 /* all data has been sent */
2540 av_freep(&c->packet_buffer);
2542 /* send RTP packet directly in UDP */
2544 url_write(c->rtp_handles[c->packet_stream_index],
2545 c->buffer_ptr, len);
2546 c->buffer_ptr += len;
2547 /* here we continue as we can send several packets per 10 ms slot */
2550 /* TCP data output */
2551 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2553 if (ff_neterrno() != AVERROR(EAGAIN) &&
2554 ff_neterrno() != AVERROR(EINTR))
2555 /* error : close connection */
2560 c->buffer_ptr += len;
2562 c->data_count += len;
2563 update_datarate(&c->datarate, c->data_count);
2565 c->stream->bytes_served += len;
2573 static int http_start_receive_data(HTTPContext *c)
2577 if (c->stream->feed_opened)
2580 /* Don't permit writing to this one */
2581 if (c->stream->readonly)
2585 fd = open(c->stream->feed_filename, O_RDWR);
2587 http_log("Error opening feeder file: %s\n", strerror(errno));
2592 if (c->stream->truncate) {
2593 /* truncate feed file */
2594 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2595 ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2596 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2598 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2599 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2604 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2605 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2606 lseek(fd, 0, SEEK_SET);
2608 /* init buffer input */
2609 c->buffer_ptr = c->buffer;
2610 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2611 c->stream->feed_opened = 1;
2612 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2616 static int http_receive_data(HTTPContext *c)
2619 int len, loop_run = 0;
2621 while (c->chunked_encoding && !c->chunk_size &&
2622 c->buffer_end > c->buffer_ptr) {
2623 /* read chunk header, if present */
2624 len = recv(c->fd, c->buffer_ptr, 1, 0);
2627 if (ff_neterrno() != AVERROR(EAGAIN) &&
2628 ff_neterrno() != AVERROR(EINTR))
2629 /* error : close connection */
2632 } else if (len == 0) {
2633 /* end of connection : close it */
2635 } else if (c->buffer_ptr - c->buffer >= 2 &&
2636 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2637 c->chunk_size = strtol(c->buffer, 0, 16);
2638 if (c->chunk_size == 0) // end of stream
2640 c->buffer_ptr = c->buffer;
2642 } else if (++loop_run > 10) {
2643 /* no chunk header, abort */
2650 if (c->buffer_end > c->buffer_ptr) {
2651 len = recv(c->fd, c->buffer_ptr,
2652 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2654 if (ff_neterrno() != AVERROR(EAGAIN) &&
2655 ff_neterrno() != AVERROR(EINTR))
2656 /* error : close connection */
2658 } else if (len == 0)
2659 /* end of connection : close it */
2662 c->chunk_size -= len;
2663 c->buffer_ptr += len;
2664 c->data_count += len;
2665 update_datarate(&c->datarate, c->data_count);
2669 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2670 if (c->buffer[0] != 'f' ||
2671 c->buffer[1] != 'm') {
2672 http_log("Feed stream has become desynchronized -- disconnecting\n");
2677 if (c->buffer_ptr >= c->buffer_end) {
2678 FFStream *feed = c->stream;
2679 /* a packet has been received : write it in the store, except
2681 if (c->data_count > FFM_PACKET_SIZE) {
2683 // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2684 /* XXX: use llseek or url_seek */
2685 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2686 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2687 http_log("Error writing to feed file: %s\n", strerror(errno));
2691 feed->feed_write_index += FFM_PACKET_SIZE;
2692 /* update file size */
2693 if (feed->feed_write_index > c->stream->feed_size)
2694 feed->feed_size = feed->feed_write_index;
2696 /* handle wrap around if max file size reached */
2697 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2698 feed->feed_write_index = FFM_PACKET_SIZE;
2701 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2702 http_log("Error writing index to feed file: %s\n", strerror(errno));
2706 /* wake up any waiting connections */
2707 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2708 if (c1->state == HTTPSTATE_WAIT_FEED &&
2709 c1->stream->feed == c->stream->feed)
2710 c1->state = HTTPSTATE_SEND_DATA;
2713 /* We have a header in our hands that contains useful data */
2714 AVFormatContext *s = avformat_alloc_context();
2716 AVInputFormat *fmt_in;
2722 /* use feed output format name to find corresponding input format */
2723 fmt_in = av_find_input_format(feed->fmt->name);
2727 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2728 0, NULL, NULL, NULL, NULL);
2732 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2737 /* Now we have the actual streams */
2738 if (s->nb_streams != feed->nb_streams) {
2739 av_close_input_stream(s);
2741 http_log("Feed '%s' stream number does not match registered feed\n",
2742 c->stream->feed_filename);
2746 for (i = 0; i < s->nb_streams; i++) {
2747 AVStream *fst = feed->streams[i];
2748 AVStream *st = s->streams[i];
2749 avcodec_copy_context(fst->codec, st->codec);
2752 av_close_input_stream(s);
2755 c->buffer_ptr = c->buffer;
2760 c->stream->feed_opened = 0;
2762 /* wake up any waiting connections to stop waiting for feed */
2763 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2764 if (c1->state == HTTPSTATE_WAIT_FEED &&
2765 c1->stream->feed == c->stream->feed)
2766 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2771 /********************************************************************/
2774 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2781 switch(error_number) {
2782 case RTSP_STATUS_OK:
2785 case RTSP_STATUS_METHOD:
2786 str = "Method Not Allowed";
2788 case RTSP_STATUS_BANDWIDTH:
2789 str = "Not Enough Bandwidth";
2791 case RTSP_STATUS_SESSION:
2792 str = "Session Not Found";
2794 case RTSP_STATUS_STATE:
2795 str = "Method Not Valid in This State";
2797 case RTSP_STATUS_AGGREGATE:
2798 str = "Aggregate operation not allowed";
2800 case RTSP_STATUS_ONLY_AGGREGATE:
2801 str = "Only aggregate operation allowed";
2803 case RTSP_STATUS_TRANSPORT:
2804 str = "Unsupported transport";
2806 case RTSP_STATUS_INTERNAL:
2807 str = "Internal Server Error";
2809 case RTSP_STATUS_SERVICE:
2810 str = "Service Unavailable";
2812 case RTSP_STATUS_VERSION:
2813 str = "RTSP Version not supported";
2816 str = "Unknown Error";
2820 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2821 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2823 /* output GMT time */
2826 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2827 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2830 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2832 rtsp_reply_header(c, error_number);
2833 avio_printf(c->pb, "\r\n");
2836 static int rtsp_parse_request(HTTPContext *c)
2838 const char *p, *p1, *p2;
2844 RTSPMessageHeader header1, *header = &header1;
2846 c->buffer_ptr[0] = '\0';
2849 get_word(cmd, sizeof(cmd), &p);
2850 get_word(url, sizeof(url), &p);
2851 get_word(protocol, sizeof(protocol), &p);
2853 av_strlcpy(c->method, cmd, sizeof(c->method));
2854 av_strlcpy(c->url, url, sizeof(c->url));
2855 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2857 if (avio_open_dyn_buf(&c->pb) < 0) {
2858 /* XXX: cannot do more */
2859 c->pb = NULL; /* safety */
2863 /* check version name */
2864 if (strcmp(protocol, "RTSP/1.0") != 0) {
2865 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2869 /* parse each header line */
2870 memset(header, 0, sizeof(*header));
2871 /* skip to next line */
2872 while (*p != '\n' && *p != '\0')
2876 while (*p != '\0') {
2877 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2881 if (p2 > p && p2[-1] == '\r')
2883 /* skip empty line */
2887 if (len > sizeof(line) - 1)
2888 len = sizeof(line) - 1;
2889 memcpy(line, p, len);
2891 ff_rtsp_parse_line(header, line, NULL, NULL);
2895 /* handle sequence number */
2896 c->seq = header->seq;
2898 if (!strcmp(cmd, "DESCRIBE"))
2899 rtsp_cmd_describe(c, url);
2900 else if (!strcmp(cmd, "OPTIONS"))
2901 rtsp_cmd_options(c, url);
2902 else if (!strcmp(cmd, "SETUP"))
2903 rtsp_cmd_setup(c, url, header);
2904 else if (!strcmp(cmd, "PLAY"))
2905 rtsp_cmd_play(c, url, header);
2906 else if (!strcmp(cmd, "PAUSE"))
2907 rtsp_cmd_pause(c, url, header);
2908 else if (!strcmp(cmd, "TEARDOWN"))
2909 rtsp_cmd_teardown(c, url, header);
2911 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2914 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2915 c->pb = NULL; /* safety */
2917 /* XXX: cannot do more */
2920 c->buffer_ptr = c->pb_buffer;
2921 c->buffer_end = c->pb_buffer + len;
2922 c->state = RTSPSTATE_SEND_REPLY;
2926 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2927 struct in_addr my_ip)
2929 AVFormatContext *avc;
2930 AVStream *avs = NULL;
2933 avc = avformat_alloc_context();
2937 av_dict_set(&avc->metadata, "title",
2938 stream->title[0] ? stream->title : "No Title", 0);
2939 avc->nb_streams = stream->nb_streams;
2940 if (stream->is_multicast) {
2941 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2942 inet_ntoa(stream->multicast_ip),
2943 stream->multicast_port, stream->multicast_ttl);
2945 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2948 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2949 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2951 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2952 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2955 for(i = 0; i < stream->nb_streams; i++) {
2956 avc->streams[i] = &avs[i];
2957 avc->streams[i]->codec = stream->streams[i]->codec;
2959 *pbuffer = av_mallocz(2048);
2960 av_sdp_create(&avc, 1, *pbuffer, 2048);
2963 av_free(avc->streams);
2964 av_dict_free(&avc->metadata);
2968 return strlen(*pbuffer);
2971 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2973 // rtsp_reply_header(c, RTSP_STATUS_OK);
2974 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2975 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2976 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2977 avio_printf(c->pb, "\r\n");
2980 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2986 int content_length, len;
2987 struct sockaddr_in my_addr;
2989 /* find which url is asked */
2990 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2995 for(stream = first_stream; stream != NULL; stream = stream->next) {
2996 if (!stream->is_feed &&
2997 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2998 !strcmp(path, stream->filename)) {
3002 /* no stream found */
3003 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3007 /* prepare the media description in sdp format */
3009 /* get the host IP */
3010 len = sizeof(my_addr);
3011 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3012 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3013 if (content_length < 0) {
3014 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3017 rtsp_reply_header(c, RTSP_STATUS_OK);
3018 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3019 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3020 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3021 avio_printf(c->pb, "\r\n");
3022 avio_write(c->pb, content, content_length);
3026 static HTTPContext *find_rtp_session(const char *session_id)
3030 if (session_id[0] == '\0')
3033 for(c = first_http_ctx; c != NULL; c = c->next) {
3034 if (!strcmp(c->session_id, session_id))
3040 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3042 RTSPTransportField *th;
3045 for(i=0;i<h->nb_transports;i++) {
3046 th = &h->transports[i];
3047 if (th->lower_transport == lower_transport)
3053 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3054 RTSPMessageHeader *h)
3057 int stream_index, rtp_port, rtcp_port;
3062 RTSPTransportField *th;
3063 struct sockaddr_in dest_addr;
3064 RTSPActionServerSetup setup;
3066 /* find which url is asked */
3067 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3072 /* now check each stream */
3073 for(stream = first_stream; stream != NULL; stream = stream->next) {
3074 if (!stream->is_feed &&
3075 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3076 /* accept aggregate filenames only if single stream */
3077 if (!strcmp(path, stream->filename)) {
3078 if (stream->nb_streams != 1) {
3079 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3086 for(stream_index = 0; stream_index < stream->nb_streams;
3088 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3089 stream->filename, stream_index);
3090 if (!strcmp(path, buf))
3095 /* no stream found */
3096 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3100 /* generate session id if needed */
3101 if (h->session_id[0] == '\0')
3102 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3103 av_lfg_get(&random_state), av_lfg_get(&random_state));
3105 /* find rtp session, and create it if none found */
3106 rtp_c = find_rtp_session(h->session_id);
3108 /* always prefer UDP */
3109 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3111 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3113 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3118 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3119 th->lower_transport);
3121 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3125 /* open input stream */
3126 if (open_input_stream(rtp_c, "") < 0) {
3127 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3132 /* test if stream is OK (test needed because several SETUP needs
3133 to be done for a given file) */
3134 if (rtp_c->stream != stream) {
3135 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3139 /* test if stream is already set up */
3140 if (rtp_c->rtp_ctx[stream_index]) {
3141 rtsp_reply_error(c, RTSP_STATUS_STATE);
3145 /* check transport */
3146 th = find_transport(h, rtp_c->rtp_protocol);
3147 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3148 th->client_port_min <= 0)) {
3149 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3153 /* setup default options */
3154 setup.transport_option[0] = '\0';
3155 dest_addr = rtp_c->from_addr;
3156 dest_addr.sin_port = htons(th->client_port_min);
3159 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3160 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3164 /* now everything is OK, so we can send the connection parameters */
3165 rtsp_reply_header(c, RTSP_STATUS_OK);
3167 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3169 switch(rtp_c->rtp_protocol) {
3170 case RTSP_LOWER_TRANSPORT_UDP:
3171 rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3172 rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3173 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3174 "client_port=%d-%d;server_port=%d-%d",
3175 th->client_port_min, th->client_port_max,
3176 rtp_port, rtcp_port);
3178 case RTSP_LOWER_TRANSPORT_TCP:
3179 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3180 stream_index * 2, stream_index * 2 + 1);
3185 if (setup.transport_option[0] != '\0')
3186 avio_printf(c->pb, ";%s", setup.transport_option);
3187 avio_printf(c->pb, "\r\n");
3190 avio_printf(c->pb, "\r\n");
3194 /* find an rtp connection by using the session ID. Check consistency
3196 static HTTPContext *find_rtp_session_with_url(const char *url,
3197 const char *session_id)
3205 rtp_c = find_rtp_session(session_id);
3209 /* find which url is asked */
3210 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3214 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3215 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3216 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3217 rtp_c->stream->filename, s);
3218 if(!strncmp(path, buf, sizeof(buf))) {
3219 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3224 if (len > 0 && path[len - 1] == '/' &&
3225 !strncmp(path, rtp_c->stream->filename, len - 1))
3230 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3234 rtp_c = find_rtp_session_with_url(url, h->session_id);
3236 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3240 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3241 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3242 rtp_c->state != HTTPSTATE_READY) {
3243 rtsp_reply_error(c, RTSP_STATUS_STATE);
3247 rtp_c->state = HTTPSTATE_SEND_DATA;
3249 /* now everything is OK, so we can send the connection parameters */
3250 rtsp_reply_header(c, RTSP_STATUS_OK);
3252 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3253 avio_printf(c->pb, "\r\n");
3256 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3260 rtp_c = find_rtp_session_with_url(url, h->session_id);
3262 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3266 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3267 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3268 rtsp_reply_error(c, RTSP_STATUS_STATE);
3272 rtp_c->state = HTTPSTATE_READY;
3273 rtp_c->first_pts = AV_NOPTS_VALUE;
3274 /* now everything is OK, so we can send the connection parameters */
3275 rtsp_reply_header(c, RTSP_STATUS_OK);
3277 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3278 avio_printf(c->pb, "\r\n");
3281 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3285 rtp_c = find_rtp_session_with_url(url, h->session_id);
3287 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3291 /* now everything is OK, so we can send the connection parameters */
3292 rtsp_reply_header(c, RTSP_STATUS_OK);
3294 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3295 avio_printf(c->pb, "\r\n");
3297 /* abort the session */
3298 close_connection(rtp_c);
3302 /********************************************************************/
3305 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3306 FFStream *stream, const char *session_id,
3307 enum RTSPLowerTransport rtp_protocol)
3309 HTTPContext *c = NULL;
3310 const char *proto_str;
3312 /* XXX: should output a warning page when coming
3313 close to the connection limit */
3314 if (nb_connections >= nb_max_connections)
3317 /* add a new connection */
3318 c = av_mallocz(sizeof(HTTPContext));
3323 c->poll_entry = NULL;
3324 c->from_addr = *from_addr;
3325 c->buffer_size = IOBUFFER_INIT_SIZE;
3326 c->buffer = av_malloc(c->buffer_size);
3331 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3332 c->state = HTTPSTATE_READY;
3333 c->is_packetized = 1;
3334 c->rtp_protocol = rtp_protocol;
3336 /* protocol is shown in statistics */
3337 switch(c->rtp_protocol) {
3338 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3339 proto_str = "MCAST";
3341 case RTSP_LOWER_TRANSPORT_UDP:
3344 case RTSP_LOWER_TRANSPORT_TCP:
3351 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3352 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3354 current_bandwidth += stream->bandwidth;
3356 c->next = first_http_ctx;
3368 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3369 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3371 static int rtp_new_av_stream(HTTPContext *c,
3372 int stream_index, struct sockaddr_in *dest_addr,
3373 HTTPContext *rtsp_c)
3375 AVFormatContext *ctx;
3378 URLContext *h = NULL;
3380 int max_packet_size;
3382 /* now we can open the relevant output stream */
3383 ctx = avformat_alloc_context();
3386 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3388 st = av_mallocz(sizeof(AVStream));
3391 ctx->nb_streams = 1;
3392 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3395 ctx->streams[0] = st;
3397 if (!c->stream->feed ||
3398 c->stream->feed == c->stream)
3399 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3402 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3404 st->priv_data = NULL;
3406 /* build destination RTP address */
3407 ipaddr = inet_ntoa(dest_addr->sin_addr);
3409 switch(c->rtp_protocol) {
3410 case RTSP_LOWER_TRANSPORT_UDP:
3411 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3414 /* XXX: also pass as parameter to function ? */
3415 if (c->stream->is_multicast) {
3417 ttl = c->stream->multicast_ttl;
3420 snprintf(ctx->filename, sizeof(ctx->filename),
3421 "rtp://%s:%d?multicast=1&ttl=%d",
3422 ipaddr, ntohs(dest_addr->sin_port), ttl);
3424 snprintf(ctx->filename, sizeof(ctx->filename),
3425 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3428 if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
3430 c->rtp_handles[stream_index] = h;
3431 max_packet_size = url_get_max_packet_size(h);
3433 case RTSP_LOWER_TRANSPORT_TCP:
3436 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3442 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3443 ipaddr, ntohs(dest_addr->sin_port),
3444 c->stream->filename, stream_index, c->protocol);
3446 /* normally, no packets should be output here, but the packet size may be checked */
3447 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3448 /* XXX: close stream */
3451 if (avformat_write_header(ctx, NULL) < 0) {
3458 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3461 c->rtp_ctx[stream_index] = ctx;
3465 /********************************************************************/
3466 /* ffserver initialization */
3468 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3472 fst = av_mallocz(sizeof(AVStream));
3476 fst->codec = avcodec_alloc_context3(NULL);
3477 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3478 if (codec->extradata_size) {
3479 fst->codec->extradata = av_malloc(codec->extradata_size);
3480 memcpy(fst->codec->extradata, codec->extradata,
3481 codec->extradata_size);
3484 /* live streams must use the actual feed's codec since it may be
3485 * updated later to carry extradata needed by the streams.
3489 fst->priv_data = av_mallocz(sizeof(FeedData));
3490 fst->index = stream->nb_streams;
3491 av_set_pts_info(fst, 33, 1, 90000);
3492 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3493 stream->streams[stream->nb_streams++] = fst;
3497 /* return the stream number in the feed */
3498 static int add_av_stream(FFStream *feed, AVStream *st)
3501 AVCodecContext *av, *av1;
3505 for(i=0;i<feed->nb_streams;i++) {
3506 st = feed->streams[i];
3508 if (av1->codec_id == av->codec_id &&
3509 av1->codec_type == av->codec_type &&
3510 av1->bit_rate == av->bit_rate) {
3512 switch(av->codec_type) {
3513 case AVMEDIA_TYPE_AUDIO:
3514 if (av1->channels == av->channels &&
3515 av1->sample_rate == av->sample_rate)
3518 case AVMEDIA_TYPE_VIDEO:
3519 if (av1->width == av->width &&
3520 av1->height == av->height &&
3521 av1->time_base.den == av->time_base.den &&
3522 av1->time_base.num == av->time_base.num &&
3523 av1->gop_size == av->gop_size)
3532 fst = add_av_stream1(feed, av, 0);
3535 return feed->nb_streams - 1;
3538 static void remove_stream(FFStream *stream)
3542 while (*ps != NULL) {
3550 /* specific mpeg4 handling : we extract the raw parameters */
3551 static void extract_mpeg4_header(AVFormatContext *infile)
3553 int mpeg4_count, i, size;
3559 for(i=0;i<infile->nb_streams;i++) {
3560 st = infile->streams[i];
3561 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3562 st->codec->extradata_size == 0) {
3569 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3570 while (mpeg4_count > 0) {
3571 if (av_read_packet(infile, &pkt) < 0)
3573 st = infile->streams[pkt.stream_index];
3574 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3575 st->codec->extradata_size == 0) {
3576 av_freep(&st->codec->extradata);
3577 /* fill extradata with the header */
3578 /* XXX: we make hard suppositions here ! */
3580 while (p < pkt.data + pkt.size - 4) {
3581 /* stop when vop header is found */
3582 if (p[0] == 0x00 && p[1] == 0x00 &&
3583 p[2] == 0x01 && p[3] == 0xb6) {
3584 size = p - pkt.data;
3585 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3586 st->codec->extradata = av_malloc(size);
3587 st->codec->extradata_size = size;
3588 memcpy(st->codec->extradata, pkt.data, size);
3595 av_free_packet(&pkt);
3599 /* compute the needed AVStream for each file */
3600 static void build_file_streams(void)
3602 FFStream *stream, *stream_next;
3605 /* gather all streams */
3606 for(stream = first_stream; stream != NULL; stream = stream_next) {
3607 AVFormatContext *infile = NULL;
3608 stream_next = stream->next;
3609 if (stream->stream_type == STREAM_TYPE_LIVE &&
3611 /* the stream comes from a file */
3612 /* try to open the file */
3614 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3615 /* specific case : if transport stream output to RTP,
3616 we use a raw transport stream reader */
3617 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3620 http_log("Opening file '%s'\n", stream->feed_filename);
3621 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3622 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3623 /* remove stream (no need to spend more time on it) */
3625 remove_stream(stream);
3627 /* find all the AVStreams inside and reference them in
3629 if (avformat_find_stream_info(infile, NULL) < 0) {
3630 http_log("Could not find codec parameters from '%s'\n",
3631 stream->feed_filename);
3632 av_close_input_file(infile);
3635 extract_mpeg4_header(infile);
3637 for(i=0;i<infile->nb_streams;i++)
3638 add_av_stream1(stream, infile->streams[i]->codec, 1);
3640 av_close_input_file(infile);
3646 /* compute the needed AVStream for each feed */
3647 static void build_feed_streams(void)
3649 FFStream *stream, *feed;
3652 /* gather all streams */
3653 for(stream = first_stream; stream != NULL; stream = stream->next) {
3654 feed = stream->feed;
3656 if (stream->is_feed) {
3657 for(i=0;i<stream->nb_streams;i++)
3658 stream->feed_streams[i] = i;
3660 /* we handle a stream coming from a feed */
3661 for(i=0;i<stream->nb_streams;i++)
3662 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3667 /* create feed files if needed */
3668 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3671 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3672 /* See if it matches */
3673 AVFormatContext *s = NULL;
3676 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3677 /* Now see if it matches */
3678 if (s->nb_streams == feed->nb_streams) {
3680 for(i=0;i<s->nb_streams;i++) {
3682 sf = feed->streams[i];
3685 if (sf->index != ss->index ||
3687 http_log("Index & Id do not match for stream %d (%s)\n",
3688 i, feed->feed_filename);
3691 AVCodecContext *ccf, *ccs;
3695 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3697 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3698 http_log("Codecs do not match for stream %d\n", i);
3700 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3701 http_log("Codec bitrates do not match for stream %d\n", i);
3703 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3704 if (CHECK_CODEC(time_base.den) ||
3705 CHECK_CODEC(time_base.num) ||
3706 CHECK_CODEC(width) ||
3707 CHECK_CODEC(height)) {
3708 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3711 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3712 if (CHECK_CODEC(sample_rate) ||
3713 CHECK_CODEC(channels) ||
3714 CHECK_CODEC(frame_size)) {
3715 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3719 http_log("Unknown codec type\n");
3727 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3728 feed->feed_filename, s->nb_streams, feed->nb_streams);
3730 av_close_input_file(s);
3732 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3733 feed->feed_filename);
3736 if (feed->readonly) {
3737 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3738 feed->feed_filename);
3741 unlink(feed->feed_filename);
3744 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3745 AVFormatContext s1 = {0}, *s = &s1;
3747 if (feed->readonly) {
3748 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3749 feed->feed_filename);
3753 /* only write the header of the ffm file */
3754 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3755 http_log("Could not open output feed file '%s'\n",
3756 feed->feed_filename);
3759 s->oformat = feed->fmt;
3760 s->nb_streams = feed->nb_streams;
3761 s->streams = feed->streams;
3762 if (avformat_write_header(s, NULL) < 0) {
3763 http_log("Container doesn't supports the required parameters\n");
3766 /* XXX: need better api */
3767 av_freep(&s->priv_data);
3770 /* get feed size and write index */
3771 fd = open(feed->feed_filename, O_RDONLY);
3773 http_log("Could not open output feed file '%s'\n",
3774 feed->feed_filename);
3778 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3779 feed->feed_size = lseek(fd, 0, SEEK_END);
3780 /* ensure that we do not wrap before the end of file */
3781 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3782 feed->feed_max_size = feed->feed_size;
3788 /* compute the bandwidth used by each stream */
3789 static void compute_bandwidth(void)
3795 for(stream = first_stream; stream != NULL; stream = stream->next) {
3797 for(i=0;i<stream->nb_streams;i++) {
3798 AVStream *st = stream->streams[i];
3799 switch(st->codec->codec_type) {
3800 case AVMEDIA_TYPE_AUDIO:
3801 case AVMEDIA_TYPE_VIDEO:
3802 bandwidth += st->codec->bit_rate;
3808 stream->bandwidth = (bandwidth + 999) / 1000;
3812 /* add a codec and set the default parameters */
3813 static void add_codec(FFStream *stream, AVCodecContext *av)
3817 /* compute default parameters */
3818 switch(av->codec_type) {
3819 case AVMEDIA_TYPE_AUDIO:
3820 if (av->bit_rate == 0)
3821 av->bit_rate = 64000;
3822 if (av->sample_rate == 0)
3823 av->sample_rate = 22050;
3824 if (av->channels == 0)
3827 case AVMEDIA_TYPE_VIDEO:
3828 if (av->bit_rate == 0)
3829 av->bit_rate = 64000;
3830 if (av->time_base.num == 0){
3831 av->time_base.den = 5;
3832 av->time_base.num = 1;
3834 if (av->width == 0 || av->height == 0) {
3838 /* Bitrate tolerance is less for streaming */
3839 if (av->bit_rate_tolerance == 0)
3840 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3841 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3846 if (av->max_qdiff == 0)
3848 av->qcompress = 0.5;
3851 if (!av->nsse_weight)
3852 av->nsse_weight = 8;
3854 av->frame_skip_cmp = FF_CMP_DCTMAX;
3856 av->me_method = ME_EPZS;
3857 av->rc_buffer_aggressivity = 1.0;
3860 av->rc_eq = "tex^qComp";
3861 if (!av->i_quant_factor)
3862 av->i_quant_factor = -0.8;
3863 if (!av->b_quant_factor)
3864 av->b_quant_factor = 1.25;
3865 if (!av->b_quant_offset)
3866 av->b_quant_offset = 1.25;
3867 if (!av->rc_max_rate)
3868 av->rc_max_rate = av->bit_rate * 2;
3870 if (av->rc_max_rate && !av->rc_buffer_size) {
3871 av->rc_buffer_size = av->rc_max_rate;
3880 st = av_mallocz(sizeof(AVStream));
3883 st->codec = avcodec_alloc_context3(NULL);
3884 stream->streams[stream->nb_streams++] = st;
3885 memcpy(st->codec, av, sizeof(AVCodecContext));
3888 static enum CodecID opt_audio_codec(const char *arg)
3890 AVCodec *p= avcodec_find_encoder_by_name(arg);
3892 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3893 return CODEC_ID_NONE;
3898 static enum CodecID opt_video_codec(const char *arg)
3900 AVCodec *p= avcodec_find_encoder_by_name(arg);
3902 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3903 return CODEC_ID_NONE;
3908 /* simplistic plugin support */
3911 static void load_module(const char *filename)
3914 void (*init_func)(void);
3915 dll = dlopen(filename, RTLD_NOW);
3917 fprintf(stderr, "Could not load module '%s' - %s\n",
3918 filename, dlerror());
3922 init_func = dlsym(dll, "ffserver_module_init");
3925 "%s: init function 'ffserver_module_init()' not found\n",
3934 static int ffserver_opt_default(const char *opt, const char *arg,
3935 AVCodecContext *avctx, int type)
3938 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3940 ret = av_set_string3(avctx, opt, arg, 1, NULL);
3944 static int ffserver_opt_preset(const char *arg,
3945 AVCodecContext *avctx, int type,
3946 enum CodecID *audio_id, enum CodecID *video_id)
3949 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3951 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3953 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3954 codec ? codec->name : NULL))) {
3955 fprintf(stderr, "File for preset '%s' not found\n", arg);
3960 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3961 if(line[0] == '#' && !e)
3963 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3965 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3969 if(!strcmp(tmp, "acodec")){
3970 *audio_id = opt_audio_codec(tmp2);
3971 }else if(!strcmp(tmp, "vcodec")){
3972 *video_id = opt_video_codec(tmp2);
3973 }else if(!strcmp(tmp, "scodec")){
3974 /* opt_subtitle_codec(tmp2); */
3975 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3976 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3987 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3988 const char *mime_type)
3990 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
3993 AVOutputFormat *stream_fmt;
3994 char stream_format_name[64];
3996 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
3997 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4006 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4010 fprintf(stderr, "%s:%d: ", filename, line_num);
4011 vfprintf(stderr, fmt, vl);
4017 static int parse_ffconfig(const char *filename)
4024 int val, errors, line_num;
4025 FFStream **last_stream, *stream, *redirect;
4026 FFStream **last_feed, *feed, *s;
4027 AVCodecContext audio_enc, video_enc;
4028 enum CodecID audio_id, video_id;
4030 f = fopen(filename, "r");
4038 first_stream = NULL;
4039 last_stream = &first_stream;
4041 last_feed = &first_feed;
4045 audio_id = CODEC_ID_NONE;
4046 video_id = CODEC_ID_NONE;
4048 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4050 if (fgets(line, sizeof(line), f) == NULL)
4056 if (*p == '\0' || *p == '#')
4059 get_arg(cmd, sizeof(cmd), &p);
4061 if (!strcasecmp(cmd, "Port")) {
4062 get_arg(arg, sizeof(arg), &p);
4064 if (val < 1 || val > 65536) {
4065 ERROR("Invalid_port: %s\n", arg);
4067 my_http_addr.sin_port = htons(val);
4068 } else if (!strcasecmp(cmd, "BindAddress")) {
4069 get_arg(arg, sizeof(arg), &p);
4070 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4071 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4073 } else if (!strcasecmp(cmd, "NoDaemon")) {
4074 ffserver_daemon = 0;
4075 } else if (!strcasecmp(cmd, "RTSPPort")) {
4076 get_arg(arg, sizeof(arg), &p);
4078 if (val < 1 || val > 65536) {
4079 ERROR("%s:%d: Invalid port: %s\n", arg);
4081 my_rtsp_addr.sin_port = htons(atoi(arg));
4082 } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4083 get_arg(arg, sizeof(arg), &p);
4084 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4085 ERROR("Invalid host/IP address: %s\n", arg);
4087 } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4088 get_arg(arg, sizeof(arg), &p);
4090 if (val < 1 || val > 65536) {
4091 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4093 nb_max_http_connections = val;
4094 } else if (!strcasecmp(cmd, "MaxClients")) {
4095 get_arg(arg, sizeof(arg), &p);
4097 if (val < 1 || val > nb_max_http_connections) {
4098 ERROR("Invalid MaxClients: %s\n", arg);
4100 nb_max_connections = val;
4102 } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4104 get_arg(arg, sizeof(arg), &p);
4106 if (llval < 10 || llval > 10000000) {
4107 ERROR("Invalid MaxBandwidth: %s\n", arg);
4109 max_bandwidth = llval;
4110 } else if (!strcasecmp(cmd, "CustomLog")) {
4111 if (!ffserver_debug)
4112 get_arg(logfilename, sizeof(logfilename), &p);
4113 } else if (!strcasecmp(cmd, "<Feed")) {
4114 /*********************************************/
4115 /* Feed related options */
4117 if (stream || feed) {
4118 ERROR("Already in a tag\n");
4120 feed = av_mallocz(sizeof(FFStream));
4121 get_arg(feed->filename, sizeof(feed->filename), &p);
4122 q = strrchr(feed->filename, '>');
4126 for (s = first_feed; s; s = s->next) {
4127 if (!strcmp(feed->filename, s->filename)) {
4128 ERROR("Feed '%s' already registered\n", s->filename);
4132 feed->fmt = av_guess_format("ffm", NULL, NULL);
4133 /* defaut feed file */
4134 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4135 "/tmp/%s.ffm", feed->filename);
4136 feed->feed_max_size = 5 * 1024 * 1024;
4138 feed->feed = feed; /* self feeding :-) */
4140 /* add in stream list */
4141 *last_stream = feed;
4142 last_stream = &feed->next;
4143 /* add in feed list */
4145 last_feed = &feed->next_feed;
4147 } else if (!strcasecmp(cmd, "Launch")) {
4151 feed->child_argv = av_mallocz(64 * sizeof(char *));
4153 for (i = 0; i < 62; i++) {
4154 get_arg(arg, sizeof(arg), &p);
4158 feed->child_argv[i] = av_strdup(arg);
4161 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4163 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4165 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4166 inet_ntoa(my_http_addr.sin_addr),
4167 ntohs(my_http_addr.sin_port), feed->filename);
4169 } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4171 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4173 } else if (stream) {
4174 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4176 } else if (!strcasecmp(cmd, "File")) {
4178 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4180 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4181 } else if (!strcasecmp(cmd, "Truncate")) {
4183 get_arg(arg, sizeof(arg), &p);
4184 feed->truncate = strtod(arg, NULL);
4186 } else if (!strcasecmp(cmd, "FileMaxSize")) {
4191 get_arg(arg, sizeof(arg), &p);
4193 fsize = strtod(p1, &p1);
4194 switch(toupper(*p1)) {
4199 fsize *= 1024 * 1024;
4202 fsize *= 1024 * 1024 * 1024;
4205 feed->feed_max_size = (int64_t)fsize;
4206 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4207 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4210 } else if (!strcasecmp(cmd, "</Feed>")) {
4212 ERROR("No corresponding <Feed> for </Feed>\n");
4215 } else if (!strcasecmp(cmd, "<Stream")) {
4216 /*********************************************/
4217 /* Stream related options */
4219 if (stream || feed) {
4220 ERROR("Already in a tag\n");
4223 stream = av_mallocz(sizeof(FFStream));
4224 get_arg(stream->filename, sizeof(stream->filename), &p);
4225 q = strrchr(stream->filename, '>');
4229 for (s = first_stream; s; s = s->next) {
4230 if (!strcmp(stream->filename, s->filename)) {
4231 ERROR("Stream '%s' already registered\n", s->filename);
4235 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4236 avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4237 avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4238 audio_id = CODEC_ID_NONE;
4239 video_id = CODEC_ID_NONE;
4241 audio_id = stream->fmt->audio_codec;
4242 video_id = stream->fmt->video_codec;
4245 *last_stream = stream;
4246 last_stream = &stream->next;
4248 } else if (!strcasecmp(cmd, "Feed")) {
4249 get_arg(arg, sizeof(arg), &p);
4254 while (sfeed != NULL) {
4255 if (!strcmp(sfeed->filename, arg))
4257 sfeed = sfeed->next_feed;
4260 ERROR("feed '%s' not defined\n", arg);
4262 stream->feed = sfeed;
4264 } else if (!strcasecmp(cmd, "Format")) {
4265 get_arg(arg, sizeof(arg), &p);
4267 if (!strcmp(arg, "status")) {
4268 stream->stream_type = STREAM_TYPE_STATUS;
4271 stream->stream_type = STREAM_TYPE_LIVE;
4272 /* jpeg cannot be used here, so use single frame jpeg */
4273 if (!strcmp(arg, "jpeg"))
4274 strcpy(arg, "mjpeg");
4275 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4277 ERROR("Unknown Format: %s\n", arg);
4281 audio_id = stream->fmt->audio_codec;
4282 video_id = stream->fmt->video_codec;
4285 } else if (!strcasecmp(cmd, "InputFormat")) {
4286 get_arg(arg, sizeof(arg), &p);
4288 stream->ifmt = av_find_input_format(arg);
4289 if (!stream->ifmt) {
4290 ERROR("Unknown input format: %s\n", arg);
4293 } else if (!strcasecmp(cmd, "FaviconURL")) {
4294 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4295 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4297 ERROR("FaviconURL only permitted for status streams\n");
4299 } else if (!strcasecmp(cmd, "Author")) {
4301 get_arg(stream->author, sizeof(stream->author), &p);
4302 } else if (!strcasecmp(cmd, "Comment")) {
4304 get_arg(stream->comment, sizeof(stream->comment), &p);
4305 } else if (!strcasecmp(cmd, "Copyright")) {
4307 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4308 } else if (!strcasecmp(cmd, "Title")) {
4310 get_arg(stream->title, sizeof(stream->title), &p);
4311 } else if (!strcasecmp(cmd, "Preroll")) {
4312 get_arg(arg, sizeof(arg), &p);
4314 stream->prebuffer = atof(arg) * 1000;
4315 } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4317 stream->send_on_key = 1;
4318 } else if (!strcasecmp(cmd, "AudioCodec")) {
4319 get_arg(arg, sizeof(arg), &p);
4320 audio_id = opt_audio_codec(arg);
4321 if (audio_id == CODEC_ID_NONE) {
4322 ERROR("Unknown AudioCodec: %s\n", arg);
4324 } else if (!strcasecmp(cmd, "VideoCodec")) {
4325 get_arg(arg, sizeof(arg), &p);
4326 video_id = opt_video_codec(arg);
4327 if (video_id == CODEC_ID_NONE) {
4328 ERROR("Unknown VideoCodec: %s\n", arg);
4330 } else if (!strcasecmp(cmd, "MaxTime")) {
4331 get_arg(arg, sizeof(arg), &p);
4333 stream->max_time = atof(arg) * 1000;
4334 } else if (!strcasecmp(cmd, "AudioBitRate")) {
4335 get_arg(arg, sizeof(arg), &p);
4337 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4338 } else if (!strcasecmp(cmd, "AudioChannels")) {
4339 get_arg(arg, sizeof(arg), &p);
4341 audio_enc.channels = atoi(arg);
4342 } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4343 get_arg(arg, sizeof(arg), &p);
4345 audio_enc.sample_rate = atoi(arg);
4346 } else if (!strcasecmp(cmd, "AudioQuality")) {
4347 get_arg(arg, sizeof(arg), &p);
4349 // audio_enc.quality = atof(arg) * 1000;
4351 } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4353 int minrate, maxrate;
4355 get_arg(arg, sizeof(arg), &p);
4357 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4358 video_enc.rc_min_rate = minrate * 1000;
4359 video_enc.rc_max_rate = maxrate * 1000;
4361 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4364 } else if (!strcasecmp(cmd, "Debug")) {
4366 get_arg(arg, sizeof(arg), &p);
4367 video_enc.debug = strtol(arg,0,0);
4369 } else if (!strcasecmp(cmd, "Strict")) {
4371 get_arg(arg, sizeof(arg), &p);
4372 video_enc.strict_std_compliance = atoi(arg);
4374 } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4376 get_arg(arg, sizeof(arg), &p);
4377 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4379 } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4381 get_arg(arg, sizeof(arg), &p);
4382 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4384 } else if (!strcasecmp(cmd, "VideoBitRate")) {
4385 get_arg(arg, sizeof(arg), &p);
4387 video_enc.bit_rate = atoi(arg) * 1000;
4389 } else if (!strcasecmp(cmd, "VideoSize")) {
4390 get_arg(arg, sizeof(arg), &p);
4392 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4393 if ((video_enc.width % 16) != 0 ||
4394 (video_enc.height % 16) != 0) {
4395 ERROR("Image size must be a multiple of 16\n");
4398 } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4399 get_arg(arg, sizeof(arg), &p);
4401 AVRational frame_rate;
4402 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4403 ERROR("Incorrect frame rate: %s\n", arg);
4405 video_enc.time_base.num = frame_rate.den;
4406 video_enc.time_base.den = frame_rate.num;
4409 } else if (!strcasecmp(cmd, "VideoGopSize")) {
4410 get_arg(arg, sizeof(arg), &p);
4412 video_enc.gop_size = atoi(arg);
4413 } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4415 video_enc.gop_size = 1;
4416 } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4418 video_enc.mb_decision = FF_MB_DECISION_BITS;
4419 } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4421 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4422 video_enc.flags |= CODEC_FLAG_4MV;
4424 } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4425 !strcasecmp(cmd, "AVOptionAudio")) {
4427 AVCodecContext *avctx;
4429 get_arg(arg, sizeof(arg), &p);
4430 get_arg(arg2, sizeof(arg2), &p);
4431 if (!strcasecmp(cmd, "AVOptionVideo")) {
4433 type = AV_OPT_FLAG_VIDEO_PARAM;
4436 type = AV_OPT_FLAG_AUDIO_PARAM;
4438 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4439 ERROR("AVOption error: %s %s\n", arg, arg2);
4441 } else if (!strcasecmp(cmd, "AVPresetVideo") ||
4442 !strcasecmp(cmd, "AVPresetAudio")) {
4443 AVCodecContext *avctx;
4445 get_arg(arg, sizeof(arg), &p);
4446 if (!strcasecmp(cmd, "AVPresetVideo")) {
4448 video_enc.codec_id = video_id;
4449 type = AV_OPT_FLAG_VIDEO_PARAM;
4452 audio_enc.codec_id = audio_id;
4453 type = AV_OPT_FLAG_AUDIO_PARAM;
4455 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4456 ERROR("AVPreset error: %s\n", arg);
4458 } else if (!strcasecmp(cmd, "VideoTag")) {
4459 get_arg(arg, sizeof(arg), &p);
4460 if ((strlen(arg) == 4) && stream)
4461 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4462 } else if (!strcasecmp(cmd, "BitExact")) {
4464 video_enc.flags |= CODEC_FLAG_BITEXACT;
4465 } else if (!strcasecmp(cmd, "DctFastint")) {
4467 video_enc.dct_algo = FF_DCT_FASTINT;
4468 } else if (!strcasecmp(cmd, "IdctSimple")) {
4470 video_enc.idct_algo = FF_IDCT_SIMPLE;
4471 } else if (!strcasecmp(cmd, "Qscale")) {
4472 get_arg(arg, sizeof(arg), &p);
4474 video_enc.flags |= CODEC_FLAG_QSCALE;
4475 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4477 } else if (!strcasecmp(cmd, "VideoQDiff")) {
4478 get_arg(arg, sizeof(arg), &p);
4480 video_enc.max_qdiff = atoi(arg);
4481 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4482 ERROR("VideoQDiff out of range\n");
4485 } else if (!strcasecmp(cmd, "VideoQMax")) {
4486 get_arg(arg, sizeof(arg), &p);
4488 video_enc.qmax = atoi(arg);
4489 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4490 ERROR("VideoQMax out of range\n");
4493 } else if (!strcasecmp(cmd, "VideoQMin")) {
4494 get_arg(arg, sizeof(arg), &p);
4496 video_enc.qmin = atoi(arg);
4497 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4498 ERROR("VideoQMin out of range\n");
4501 } else if (!strcasecmp(cmd, "LumaElim")) {
4502 get_arg(arg, sizeof(arg), &p);
4504 video_enc.luma_elim_threshold = atoi(arg);
4505 } else if (!strcasecmp(cmd, "ChromaElim")) {
4506 get_arg(arg, sizeof(arg), &p);
4508 video_enc.chroma_elim_threshold = atoi(arg);
4509 } else if (!strcasecmp(cmd, "LumiMask")) {
4510 get_arg(arg, sizeof(arg), &p);
4512 video_enc.lumi_masking = atof(arg);
4513 } else if (!strcasecmp(cmd, "DarkMask")) {
4514 get_arg(arg, sizeof(arg), &p);
4516 video_enc.dark_masking = atof(arg);
4517 } else if (!strcasecmp(cmd, "NoVideo")) {
4518 video_id = CODEC_ID_NONE;
4519 } else if (!strcasecmp(cmd, "NoAudio")) {
4520 audio_id = CODEC_ID_NONE;
4521 } else if (!strcasecmp(cmd, "ACL")) {
4522 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4523 } else if (!strcasecmp(cmd, "DynamicACL")) {
4525 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4527 } else if (!strcasecmp(cmd, "RTSPOption")) {
4528 get_arg(arg, sizeof(arg), &p);
4530 av_freep(&stream->rtsp_option);
4531 stream->rtsp_option = av_strdup(arg);
4533 } else if (!strcasecmp(cmd, "MulticastAddress")) {
4534 get_arg(arg, sizeof(arg), &p);
4536 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4537 ERROR("Invalid host/IP address: %s\n", arg);
4539 stream->is_multicast = 1;
4540 stream->loop = 1; /* default is looping */
4542 } else if (!strcasecmp(cmd, "MulticastPort")) {
4543 get_arg(arg, sizeof(arg), &p);
4545 stream->multicast_port = atoi(arg);
4546 } else if (!strcasecmp(cmd, "MulticastTTL")) {
4547 get_arg(arg, sizeof(arg), &p);
4549 stream->multicast_ttl = atoi(arg);
4550 } else if (!strcasecmp(cmd, "NoLoop")) {
4553 } else if (!strcasecmp(cmd, "</Stream>")) {
4555 ERROR("No corresponding <Stream> for </Stream>\n");
4557 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4558 if (audio_id != CODEC_ID_NONE) {
4559 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4560 audio_enc.codec_id = audio_id;
4561 add_codec(stream, &audio_enc);
4563 if (video_id != CODEC_ID_NONE) {
4564 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4565 video_enc.codec_id = video_id;
4566 add_codec(stream, &video_enc);
4571 } else if (!strcasecmp(cmd, "<Redirect")) {
4572 /*********************************************/
4574 if (stream || feed || redirect) {
4575 ERROR("Already in a tag\n");
4577 redirect = av_mallocz(sizeof(FFStream));
4578 *last_stream = redirect;
4579 last_stream = &redirect->next;
4581 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4582 q = strrchr(redirect->filename, '>');
4585 redirect->stream_type = STREAM_TYPE_REDIRECT;
4587 } else if (!strcasecmp(cmd, "URL")) {
4589 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4590 } else if (!strcasecmp(cmd, "</Redirect>")) {
4592 ERROR("No corresponding <Redirect> for </Redirect>\n");
4594 if (!redirect->feed_filename[0]) {
4595 ERROR("No URL found for <Redirect>\n");
4599 } else if (!strcasecmp(cmd, "LoadModule")) {
4600 get_arg(arg, sizeof(arg), &p);
4604 ERROR("Module support not compiled into this version: '%s'\n", arg);
4607 ERROR("Incorrect keyword: '%s'\n", cmd);
4619 static void handle_child_exit(int sig)
4624 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4627 for (feed = first_feed; feed; feed = feed->next) {
4628 if (feed->pid == pid) {
4629 int uptime = time(0) - feed->pid_start;
4632 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4635 /* Turn off any more restarts */
4636 feed->child_argv = 0;
4641 need_to_start_children = 1;
4644 static void opt_debug(void)
4647 ffserver_daemon = 0;
4648 logfilename[0] = '-';
4651 static int opt_help(const char *opt, const char *arg)
4653 printf("usage: ffserver [options]\n"
4654 "Hyper fast multi format Audio/Video streaming server\n");
4656 show_help_options(options, "Main options:\n", 0, 0);
4660 static const OptionDef options[] = {
4661 #include "cmdutils_common_opts.h"
4662 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4663 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4664 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4668 int main(int argc, char **argv)
4670 struct sigaction sigact;
4676 my_program_name = argv[0];
4677 my_program_dir = getcwd(0, 0);
4678 ffserver_daemon = 1;
4680 parse_options(NULL, argc, argv, options, NULL);
4682 unsetenv("http_proxy"); /* Kill the http_proxy */
4684 av_lfg_init(&random_state, av_get_random_seed());
4686 memset(&sigact, 0, sizeof(sigact));
4687 sigact.sa_handler = handle_child_exit;
4688 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4689 sigaction(SIGCHLD, &sigact, 0);
4691 if (parse_ffconfig(config_filename) < 0) {
4692 fprintf(stderr, "Incorrect config file - exiting.\n");
4696 /* open log file if needed */
4697 if (logfilename[0] != '\0') {
4698 if (!strcmp(logfilename, "-"))
4701 logfile = fopen(logfilename, "a");
4702 av_log_set_callback(http_av_log);
4705 build_file_streams();
4707 build_feed_streams();
4709 compute_bandwidth();
4711 /* put the process in background and detach it from its TTY */
4712 if (ffserver_daemon) {
4719 } else if (pid > 0) {
4726 open("/dev/null", O_RDWR);
4727 if (strcmp(logfilename, "-") != 0) {
4737 signal(SIGPIPE, SIG_IGN);
4739 if (ffserver_daemon)
4742 if (http_server() < 0) {
4743 http_log("Could not start server\n");