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
28 #include "libavformat/avformat.h"
29 #include "libavformat/ffm.h"
30 #include "libavformat/network.h"
31 #include "libavformat/os_support.h"
32 #include "libavformat/rtpdec.h"
33 #include "libavformat/rtsp.h"
34 // XXX for ffio_open_dyn_packet_buffer, to be removed
35 #include "libavformat/avio_internal.h"
36 #include "libavutil/avstring.h"
37 #include "libavutil/lfg.h"
38 #include "libavutil/dict.h"
39 #include "libavutil/mathematics.h"
40 #include "libavutil/random_seed.h"
41 #include "libavutil/parseutils.h"
42 #include "libavutil/opt.h"
46 #include <sys/ioctl.h>
61 const char program_name[] = "ffserver";
62 const int program_birth_year = 2000;
64 static const OptionDef options[];
67 HTTPSTATE_WAIT_REQUEST,
68 HTTPSTATE_SEND_HEADER,
69 HTTPSTATE_SEND_DATA_HEADER,
70 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
71 HTTPSTATE_SEND_DATA_TRAILER,
72 HTTPSTATE_RECEIVE_DATA,
73 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
76 RTSPSTATE_WAIT_REQUEST,
78 RTSPSTATE_SEND_PACKET,
81 static const char *http_state[] = {
97 #define MAX_STREAMS 20
99 #define IOBUFFER_INIT_SIZE 8192
101 /* timeouts are in ms */
102 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
103 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
105 #define SYNC_TIMEOUT (10 * 1000)
107 typedef struct RTSPActionServerSetup {
109 char transport_option[512];
110 } RTSPActionServerSetup;
113 int64_t count1, count2;
114 int64_t time1, time2;
117 /* context associated with one connection */
118 typedef struct HTTPContext {
119 enum HTTPState state;
120 int fd; /* socket file descriptor */
121 struct sockaddr_in from_addr; /* origin */
122 struct pollfd *poll_entry; /* used when polling */
124 uint8_t *buffer_ptr, *buffer_end;
127 int chunked_encoding;
128 int chunk_size; /* 0 if it needs to be read */
129 struct HTTPContext *next;
130 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
134 /* input format handling */
135 AVFormatContext *fmt_in;
136 int64_t start_time; /* In milliseconds - this wraps fairly often */
137 int64_t first_pts; /* initial pts value */
138 int64_t cur_pts; /* current pts value from the stream in us */
139 int64_t cur_frame_duration; /* duration of the current frame in us */
140 int cur_frame_bytes; /* output frame size, needed to compute
141 the time at which we send each
143 int pts_stream_index; /* stream we choose as clock reference */
144 int64_t cur_clock; /* current clock reference value in us */
145 /* output format handling */
146 struct FFStream *stream;
147 /* -1 is invalid stream */
148 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
149 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
151 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
152 int last_packet_sent; /* true if last data packet was sent */
154 DataRateData datarate;
161 int is_packetized; /* if true, the stream is packetized */
162 int packet_stream_index; /* current stream for output in state machine */
164 /* RTSP state specific */
165 uint8_t *pb_buffer; /* XXX: use that in all the code */
167 int seq; /* RTSP sequence number */
169 /* RTP state specific */
170 enum RTSPLowerTransport rtp_protocol;
171 char session_id[32]; /* session id */
172 AVFormatContext *rtp_ctx[MAX_STREAMS];
174 /* RTP/UDP specific */
175 URLContext *rtp_handles[MAX_STREAMS];
177 /* RTP/TCP specific */
178 struct HTTPContext *rtsp_c;
179 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
182 /* each generated stream is described here */
186 STREAM_TYPE_REDIRECT,
189 enum IPAddressAction {
194 typedef struct IPAddressACL {
195 struct IPAddressACL *next;
196 enum IPAddressAction action;
197 /* These are in host order */
198 struct in_addr first;
202 /* description of each stream of the ffserver.conf file */
203 typedef struct FFStream {
204 enum StreamType stream_type;
205 char filename[1024]; /* stream filename */
206 struct FFStream *feed; /* feed we are using (can be null if
208 AVDictionary *in_opts; /* input parameters */
209 AVInputFormat *ifmt; /* if non NULL, force input format */
212 char dynamic_acl[1024];
214 int prebuffer; /* Number of millseconds early to start */
215 int64_t max_time; /* Number of milliseconds to run */
217 AVStream *streams[MAX_STREAMS];
218 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
219 char feed_filename[1024]; /* file name of the feed storage, or
220 input file name for a stream */
225 pid_t pid; /* Of ffmpeg process */
226 time_t pid_start; /* Of ffmpeg process */
228 struct FFStream *next;
229 unsigned bandwidth; /* bandwidth, in kbits/s */
232 /* multicast specific */
234 struct in_addr multicast_ip;
235 int multicast_port; /* first port used for multicast */
237 int loop; /* if true, send the stream in loops (only meaningful if file) */
240 int feed_opened; /* true if someone is writing to the feed */
241 int is_feed; /* true if it is a feed */
242 int readonly; /* True if writing is prohibited to the file */
243 int truncate; /* True if feeder connection truncate the feed file */
245 int64_t bytes_served;
246 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
247 int64_t feed_write_index; /* current write position in feed (it wraps around) */
248 int64_t feed_size; /* current size of feed */
249 struct FFStream *next_feed;
252 typedef struct FeedData {
253 long long data_count;
254 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
257 static struct sockaddr_in my_http_addr;
258 static struct sockaddr_in my_rtsp_addr;
260 static char logfilename[1024];
261 static HTTPContext *first_http_ctx;
262 static FFStream *first_feed; /* contains only feeds */
263 static FFStream *first_stream; /* contains all streams, including feeds */
265 static void new_connection(int server_fd, int is_rtsp);
266 static void close_connection(HTTPContext *c);
269 static int handle_connection(HTTPContext *c);
270 static int http_parse_request(HTTPContext *c);
271 static int http_send_data(HTTPContext *c);
272 static void compute_status(HTTPContext *c);
273 static int open_input_stream(HTTPContext *c, const char *info);
274 static int http_start_receive_data(HTTPContext *c);
275 static int http_receive_data(HTTPContext *c);
278 static int rtsp_parse_request(HTTPContext *c);
279 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
280 static void rtsp_cmd_options(HTTPContext *c, const char *url);
281 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
282 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
283 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
284 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
287 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
288 struct in_addr my_ip);
291 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
292 FFStream *stream, const char *session_id,
293 enum RTSPLowerTransport rtp_protocol);
294 static int rtp_new_av_stream(HTTPContext *c,
295 int stream_index, struct sockaddr_in *dest_addr,
296 HTTPContext *rtsp_c);
298 static const char *my_program_name;
299 static const char *my_program_dir;
301 static const char *config_filename = "/etc/ffserver.conf";
303 static int ffserver_debug;
304 static int ffserver_daemon;
305 static int no_launch;
306 static int need_to_start_children;
308 /* maximum number of simultaneous HTTP connections */
309 static unsigned int nb_max_http_connections = 2000;
310 static unsigned int nb_max_connections = 5;
311 static unsigned int nb_connections;
313 static uint64_t max_bandwidth = 1000;
314 static uint64_t current_bandwidth;
316 static int64_t cur_time; // Making this global saves on passing it around everywhere
318 static AVLFG random_state;
320 static FILE *logfile = NULL;
322 /* FIXME: make ffserver work with IPv6 */
323 void av_noreturn exit_program(int ret)
328 /* resolve host with also IP address parsing */
329 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
332 if (!ff_inet_aton(hostname, sin_addr)) {
334 struct addrinfo *ai, *cur;
335 struct addrinfo hints;
336 memset(&hints, 0, sizeof(hints));
337 hints.ai_family = AF_INET;
338 if (getaddrinfo(hostname, NULL, &hints, &ai))
340 /* getaddrinfo returns a linked list of addrinfo structs.
341 * Even if we set ai_family = AF_INET above, make sure
342 * that the returned one actually is of the correct type. */
343 for (cur = ai; cur; cur = cur->ai_next) {
344 if (cur->ai_family == AF_INET) {
345 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
354 hp = gethostbyname(hostname);
357 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
363 static char *ctime1(char *buf2)
371 p = buf2 + strlen(p) - 1;
377 static void http_vlog(const char *fmt, va_list vargs)
379 static int print_prefix = 1;
384 fprintf(logfile, "%s ", buf);
386 print_prefix = strstr(fmt, "\n") != NULL;
387 vfprintf(logfile, fmt, vargs);
393 __attribute__ ((format (printf, 1, 2)))
395 static void http_log(const char *fmt, ...)
398 va_start(vargs, fmt);
399 http_vlog(fmt, vargs);
403 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
405 static int print_prefix = 1;
406 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
407 if (level > av_log_get_level())
409 if (print_prefix && avc)
410 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
411 print_prefix = strstr(fmt, "\n") != NULL;
412 http_vlog(fmt, vargs);
415 static void log_connection(HTTPContext *c)
420 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
421 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
422 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
425 static void update_datarate(DataRateData *drd, int64_t count)
427 if (!drd->time1 && !drd->count1) {
428 drd->time1 = drd->time2 = cur_time;
429 drd->count1 = drd->count2 = count;
430 } else if (cur_time - drd->time2 > 5000) {
431 drd->time1 = drd->time2;
432 drd->count1 = drd->count2;
433 drd->time2 = cur_time;
438 /* In bytes per second */
439 static int compute_datarate(DataRateData *drd, int64_t count)
441 if (cur_time == drd->time1)
444 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
448 static void start_children(FFStream *feed)
453 for (; feed; feed = feed->next) {
454 if (feed->child_argv && !feed->pid) {
455 feed->pid_start = time(0);
460 http_log("Unable to create children\n");
469 av_strlcpy(pathname, my_program_name, sizeof(pathname));
471 slash = strrchr(pathname, '/');
476 strcpy(slash, "ffmpeg");
478 http_log("Launch commandline: ");
479 http_log("%s ", pathname);
480 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
481 http_log("%s ", feed->child_argv[i]);
484 for (i = 3; i < 256; i++)
487 if (!ffserver_debug) {
488 i = open("/dev/null", O_RDWR);
497 /* This is needed to make relative pathnames work */
498 chdir(my_program_dir);
500 signal(SIGPIPE, SIG_DFL);
502 execvp(pathname, feed->child_argv);
510 /* open a listening socket */
511 static int socket_open_listen(struct sockaddr_in *my_addr)
515 server_fd = socket(AF_INET,SOCK_STREAM,0);
522 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
524 my_addr->sin_family = AF_INET;
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 (av_strncasecmp(p, "Pragma:", 7) == 0) {
1088 const char *q = p + 7;
1090 while (*q && *q != '\n' && isspace(*q))
1093 if (av_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 (av_strcasecmp(arg, "allow") == 0)
1274 acl.action = IP_ALLOW;
1275 else if (av_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 (!av_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 (av_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 || av_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 (av_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 (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1748 if (av_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 = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3172 rtcp_port = ff_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_opt_set(avctx, opt, arg, 0);
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 (!av_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 (!av_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 (!av_strcasecmp(cmd, "NoDaemon")) {
4074 ffserver_daemon = 0;
4075 } else if (!av_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 (!av_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 (!av_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 (!av_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 (!av_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 (!av_strcasecmp(cmd, "CustomLog")) {
4111 if (!ffserver_debug)
4112 get_arg(logfilename, sizeof(logfilename), &p);
4113 } else if (!av_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 (!av_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 (!av_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 (!av_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 (!av_strcasecmp(cmd, "Truncate")) {
4183 get_arg(arg, sizeof(arg), &p);
4184 feed->truncate = strtod(arg, NULL);
4186 } else if (!av_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 (!av_strcasecmp(cmd, "</Feed>")) {
4212 ERROR("No corresponding <Feed> for </Feed>\n");
4215 } else if (!av_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);
4239 audio_id = CODEC_ID_NONE;
4240 video_id = CODEC_ID_NONE;
4242 audio_id = stream->fmt->audio_codec;
4243 video_id = stream->fmt->video_codec;
4246 *last_stream = stream;
4247 last_stream = &stream->next;
4249 } else if (!av_strcasecmp(cmd, "Feed")) {
4250 get_arg(arg, sizeof(arg), &p);
4255 while (sfeed != NULL) {
4256 if (!strcmp(sfeed->filename, arg))
4258 sfeed = sfeed->next_feed;
4261 ERROR("feed '%s' not defined\n", arg);
4263 stream->feed = sfeed;
4265 } else if (!av_strcasecmp(cmd, "Format")) {
4266 get_arg(arg, sizeof(arg), &p);
4268 if (!strcmp(arg, "status")) {
4269 stream->stream_type = STREAM_TYPE_STATUS;
4272 stream->stream_type = STREAM_TYPE_LIVE;
4273 /* jpeg cannot be used here, so use single frame jpeg */
4274 if (!strcmp(arg, "jpeg"))
4275 strcpy(arg, "mjpeg");
4276 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4278 ERROR("Unknown Format: %s\n", arg);
4282 audio_id = stream->fmt->audio_codec;
4283 video_id = stream->fmt->video_codec;
4286 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4287 get_arg(arg, sizeof(arg), &p);
4289 stream->ifmt = av_find_input_format(arg);
4290 if (!stream->ifmt) {
4291 ERROR("Unknown input format: %s\n", arg);
4294 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4295 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4296 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4298 ERROR("FaviconURL only permitted for status streams\n");
4300 } else if (!av_strcasecmp(cmd, "Author")) {
4302 get_arg(stream->author, sizeof(stream->author), &p);
4303 } else if (!av_strcasecmp(cmd, "Comment")) {
4305 get_arg(stream->comment, sizeof(stream->comment), &p);
4306 } else if (!av_strcasecmp(cmd, "Copyright")) {
4308 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4309 } else if (!av_strcasecmp(cmd, "Title")) {
4311 get_arg(stream->title, sizeof(stream->title), &p);
4312 } else if (!av_strcasecmp(cmd, "Preroll")) {
4313 get_arg(arg, sizeof(arg), &p);
4315 stream->prebuffer = atof(arg) * 1000;
4316 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4318 stream->send_on_key = 1;
4319 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4320 get_arg(arg, sizeof(arg), &p);
4321 audio_id = opt_audio_codec(arg);
4322 if (audio_id == CODEC_ID_NONE) {
4323 ERROR("Unknown AudioCodec: %s\n", arg);
4325 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4326 get_arg(arg, sizeof(arg), &p);
4327 video_id = opt_video_codec(arg);
4328 if (video_id == CODEC_ID_NONE) {
4329 ERROR("Unknown VideoCodec: %s\n", arg);
4331 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4332 get_arg(arg, sizeof(arg), &p);
4334 stream->max_time = atof(arg) * 1000;
4335 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4336 get_arg(arg, sizeof(arg), &p);
4338 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4339 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4340 get_arg(arg, sizeof(arg), &p);
4342 audio_enc.channels = atoi(arg);
4343 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4344 get_arg(arg, sizeof(arg), &p);
4346 audio_enc.sample_rate = atoi(arg);
4347 } else if (!av_strcasecmp(cmd, "AudioQuality")) {
4348 get_arg(arg, sizeof(arg), &p);
4350 // audio_enc.quality = atof(arg) * 1000;
4352 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4354 int minrate, maxrate;
4356 get_arg(arg, sizeof(arg), &p);
4358 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4359 video_enc.rc_min_rate = minrate * 1000;
4360 video_enc.rc_max_rate = maxrate * 1000;
4362 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4365 } else if (!av_strcasecmp(cmd, "Debug")) {
4367 get_arg(arg, sizeof(arg), &p);
4368 video_enc.debug = strtol(arg,0,0);
4370 } else if (!av_strcasecmp(cmd, "Strict")) {
4372 get_arg(arg, sizeof(arg), &p);
4373 video_enc.strict_std_compliance = atoi(arg);
4375 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4377 get_arg(arg, sizeof(arg), &p);
4378 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4380 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4382 get_arg(arg, sizeof(arg), &p);
4383 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4385 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4386 get_arg(arg, sizeof(arg), &p);
4388 video_enc.bit_rate = atoi(arg) * 1000;
4390 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4391 get_arg(arg, sizeof(arg), &p);
4393 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4394 if ((video_enc.width % 16) != 0 ||
4395 (video_enc.height % 16) != 0) {
4396 ERROR("Image size must be a multiple of 16\n");
4399 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4400 get_arg(arg, sizeof(arg), &p);
4402 AVRational frame_rate;
4403 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4404 ERROR("Incorrect frame rate: %s\n", arg);
4406 video_enc.time_base.num = frame_rate.den;
4407 video_enc.time_base.den = frame_rate.num;
4410 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4411 get_arg(arg, sizeof(arg), &p);
4413 video_enc.gop_size = atoi(arg);
4414 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4416 video_enc.gop_size = 1;
4417 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4419 video_enc.mb_decision = FF_MB_DECISION_BITS;
4420 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4422 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4423 video_enc.flags |= CODEC_FLAG_4MV;
4425 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4426 !av_strcasecmp(cmd, "AVOptionAudio")) {
4428 AVCodecContext *avctx;
4430 get_arg(arg, sizeof(arg), &p);
4431 get_arg(arg2, sizeof(arg2), &p);
4432 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4434 type = AV_OPT_FLAG_VIDEO_PARAM;
4437 type = AV_OPT_FLAG_AUDIO_PARAM;
4439 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4440 ERROR("AVOption error: %s %s\n", arg, arg2);
4442 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4443 !av_strcasecmp(cmd, "AVPresetAudio")) {
4444 AVCodecContext *avctx;
4446 get_arg(arg, sizeof(arg), &p);
4447 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4449 video_enc.codec_id = video_id;
4450 type = AV_OPT_FLAG_VIDEO_PARAM;
4453 audio_enc.codec_id = audio_id;
4454 type = AV_OPT_FLAG_AUDIO_PARAM;
4456 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4457 ERROR("AVPreset error: %s\n", arg);
4459 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4460 get_arg(arg, sizeof(arg), &p);
4461 if ((strlen(arg) == 4) && stream)
4462 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4463 } else if (!av_strcasecmp(cmd, "BitExact")) {
4465 video_enc.flags |= CODEC_FLAG_BITEXACT;
4466 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4468 video_enc.dct_algo = FF_DCT_FASTINT;
4469 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4471 video_enc.idct_algo = FF_IDCT_SIMPLE;
4472 } else if (!av_strcasecmp(cmd, "Qscale")) {
4473 get_arg(arg, sizeof(arg), &p);
4475 video_enc.flags |= CODEC_FLAG_QSCALE;
4476 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4478 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4479 get_arg(arg, sizeof(arg), &p);
4481 video_enc.max_qdiff = atoi(arg);
4482 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4483 ERROR("VideoQDiff out of range\n");
4486 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4487 get_arg(arg, sizeof(arg), &p);
4489 video_enc.qmax = atoi(arg);
4490 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4491 ERROR("VideoQMax out of range\n");
4494 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4495 get_arg(arg, sizeof(arg), &p);
4497 video_enc.qmin = atoi(arg);
4498 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4499 ERROR("VideoQMin out of range\n");
4502 } else if (!av_strcasecmp(cmd, "LumaElim")) {
4503 get_arg(arg, sizeof(arg), &p);
4505 video_enc.luma_elim_threshold = atoi(arg);
4506 } else if (!av_strcasecmp(cmd, "ChromaElim")) {
4507 get_arg(arg, sizeof(arg), &p);
4509 video_enc.chroma_elim_threshold = atoi(arg);
4510 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4511 get_arg(arg, sizeof(arg), &p);
4513 video_enc.lumi_masking = atof(arg);
4514 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4515 get_arg(arg, sizeof(arg), &p);
4517 video_enc.dark_masking = atof(arg);
4518 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4519 video_id = CODEC_ID_NONE;
4520 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4521 audio_id = CODEC_ID_NONE;
4522 } else if (!av_strcasecmp(cmd, "ACL")) {
4523 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4524 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4526 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4528 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4529 get_arg(arg, sizeof(arg), &p);
4531 av_freep(&stream->rtsp_option);
4532 stream->rtsp_option = av_strdup(arg);
4534 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4535 get_arg(arg, sizeof(arg), &p);
4537 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4538 ERROR("Invalid host/IP address: %s\n", arg);
4540 stream->is_multicast = 1;
4541 stream->loop = 1; /* default is looping */
4543 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4544 get_arg(arg, sizeof(arg), &p);
4546 stream->multicast_port = atoi(arg);
4547 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4548 get_arg(arg, sizeof(arg), &p);
4550 stream->multicast_ttl = atoi(arg);
4551 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4554 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4556 ERROR("No corresponding <Stream> for </Stream>\n");
4558 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4559 if (audio_id != CODEC_ID_NONE) {
4560 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4561 audio_enc.codec_id = audio_id;
4562 add_codec(stream, &audio_enc);
4564 if (video_id != CODEC_ID_NONE) {
4565 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4566 video_enc.codec_id = video_id;
4567 add_codec(stream, &video_enc);
4572 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4573 /*********************************************/
4575 if (stream || feed || redirect) {
4576 ERROR("Already in a tag\n");
4578 redirect = av_mallocz(sizeof(FFStream));
4579 *last_stream = redirect;
4580 last_stream = &redirect->next;
4582 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4583 q = strrchr(redirect->filename, '>');
4586 redirect->stream_type = STREAM_TYPE_REDIRECT;
4588 } else if (!av_strcasecmp(cmd, "URL")) {
4590 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4591 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4593 ERROR("No corresponding <Redirect> for </Redirect>\n");
4595 if (!redirect->feed_filename[0]) {
4596 ERROR("No URL found for <Redirect>\n");
4600 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4601 get_arg(arg, sizeof(arg), &p);
4605 ERROR("Module support not compiled into this version: '%s'\n", arg);
4608 ERROR("Incorrect keyword: '%s'\n", cmd);
4620 static void handle_child_exit(int sig)
4625 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4628 for (feed = first_feed; feed; feed = feed->next) {
4629 if (feed->pid == pid) {
4630 int uptime = time(0) - feed->pid_start;
4633 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4636 /* Turn off any more restarts */
4637 feed->child_argv = 0;
4642 need_to_start_children = 1;
4645 static void opt_debug(void)
4648 ffserver_daemon = 0;
4649 logfilename[0] = '-';
4652 static int opt_help(const char *opt, const char *arg)
4654 printf("usage: ffserver [options]\n"
4655 "Hyper fast multi format Audio/Video streaming server\n");
4657 show_help_options(options, "Main options:\n", 0, 0);
4661 static const OptionDef options[] = {
4662 #include "cmdutils_common_opts.h"
4663 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4664 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4665 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4669 int main(int argc, char **argv)
4671 struct sigaction sigact;
4673 parse_loglevel(argc, argv, options);
4675 avformat_network_init();
4679 my_program_name = argv[0];
4680 my_program_dir = getcwd(0, 0);
4681 ffserver_daemon = 1;
4683 parse_options(NULL, argc, argv, options, NULL);
4685 unsetenv("http_proxy"); /* Kill the http_proxy */
4687 av_lfg_init(&random_state, av_get_random_seed());
4689 memset(&sigact, 0, sizeof(sigact));
4690 sigact.sa_handler = handle_child_exit;
4691 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4692 sigaction(SIGCHLD, &sigact, 0);
4694 if (parse_ffconfig(config_filename) < 0) {
4695 fprintf(stderr, "Incorrect config file - exiting.\n");
4699 /* open log file if needed */
4700 if (logfilename[0] != '\0') {
4701 if (!strcmp(logfilename, "-"))
4704 logfile = fopen(logfilename, "a");
4705 av_log_set_callback(http_av_log);
4708 build_file_streams();
4710 build_feed_streams();
4712 compute_bandwidth();
4714 /* put the process in background and detach it from its TTY */
4715 if (ffserver_daemon) {
4722 } else if (pid > 0) {
4729 open("/dev/null", O_RDWR);
4730 if (strcmp(logfilename, "-") != 0) {
4740 signal(SIGPIPE, SIG_IGN);
4742 if (ffserver_daemon)
4745 if (http_server() < 0) {
4746 http_log("Could not start server\n");