2 * Multiple format streaming server
3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #define closesocket close
29 #include "libavformat/avformat.h"
30 #include "libavformat/ffm.h"
31 #include "libavformat/network.h"
32 #include "libavformat/os_support.h"
33 #include "libavformat/rtpdec.h"
34 #include "libavformat/rtsp.h"
35 // XXX for ffio_open_dyn_packet_buffer, to be removed
36 #include "libavformat/avio_internal.h"
37 #include "libavutil/avstring.h"
38 #include "libavutil/lfg.h"
39 #include "libavutil/dict.h"
40 #include "libavutil/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 AVFormatParameters *ap_in; /* 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 /* resolve host with also IP address parsing */
324 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
327 if (!ff_inet_aton(hostname, sin_addr)) {
329 struct addrinfo *ai, *cur;
330 struct addrinfo hints;
331 memset(&hints, 0, sizeof(hints));
332 hints.ai_family = AF_INET;
333 if (getaddrinfo(hostname, NULL, &hints, &ai))
335 /* getaddrinfo returns a linked list of addrinfo structs.
336 * Even if we set ai_family = AF_INET above, make sure
337 * that the returned one actually is of the correct type. */
338 for (cur = ai; cur; cur = cur->ai_next) {
339 if (cur->ai_family == AF_INET) {
340 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
349 hp = gethostbyname(hostname);
352 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
358 static char *ctime1(char *buf2)
366 p = buf2 + strlen(p) - 1;
372 static void http_vlog(const char *fmt, va_list vargs)
374 static int print_prefix = 1;
379 fprintf(logfile, "%s ", buf);
381 print_prefix = strstr(fmt, "\n") != NULL;
382 vfprintf(logfile, fmt, vargs);
388 __attribute__ ((format (printf, 1, 2)))
390 static void http_log(const char *fmt, ...)
393 va_start(vargs, fmt);
394 http_vlog(fmt, vargs);
398 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
400 static int print_prefix = 1;
401 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
402 if (level > av_log_get_level())
404 if (print_prefix && avc)
405 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
406 print_prefix = strstr(fmt, "\n") != NULL;
407 http_vlog(fmt, vargs);
410 static void log_connection(HTTPContext *c)
415 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
416 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
417 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
420 static void update_datarate(DataRateData *drd, int64_t count)
422 if (!drd->time1 && !drd->count1) {
423 drd->time1 = drd->time2 = cur_time;
424 drd->count1 = drd->count2 = count;
425 } else if (cur_time - drd->time2 > 5000) {
426 drd->time1 = drd->time2;
427 drd->count1 = drd->count2;
428 drd->time2 = cur_time;
433 /* In bytes per second */
434 static int compute_datarate(DataRateData *drd, int64_t count)
436 if (cur_time == drd->time1)
439 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
443 static void start_children(FFStream *feed)
448 for (; feed; feed = feed->next) {
449 if (feed->child_argv && !feed->pid) {
450 feed->pid_start = time(0);
455 http_log("Unable to create children\n");
464 av_strlcpy(pathname, my_program_name, sizeof(pathname));
466 slash = strrchr(pathname, '/');
471 strcpy(slash, "ffmpeg");
473 http_log("Launch commandline: ");
474 http_log("%s ", pathname);
475 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
476 http_log("%s ", feed->child_argv[i]);
479 for (i = 3; i < 256; i++)
482 if (!ffserver_debug) {
483 i = open("/dev/null", O_RDWR);
492 /* This is needed to make relative pathnames work */
493 chdir(my_program_dir);
495 signal(SIGPIPE, SIG_DFL);
497 execvp(pathname, feed->child_argv);
505 /* open a listening socket */
506 static int socket_open_listen(struct sockaddr_in *my_addr)
510 server_fd = socket(AF_INET,SOCK_STREAM,0);
517 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
519 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
521 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
523 closesocket(server_fd);
527 if (listen (server_fd, 5) < 0) {
529 closesocket(server_fd);
532 ff_socket_nonblock(server_fd, 1);
537 /* start all multicast streams */
538 static void start_multicast(void)
543 struct sockaddr_in dest_addr;
544 int default_port, stream_index;
547 for(stream = first_stream; stream != NULL; stream = stream->next) {
548 if (stream->is_multicast) {
549 /* open the RTP connection */
550 snprintf(session_id, sizeof(session_id), "%08x%08x",
551 av_lfg_get(&random_state), av_lfg_get(&random_state));
553 /* choose a port if none given */
554 if (stream->multicast_port == 0) {
555 stream->multicast_port = default_port;
559 dest_addr.sin_family = AF_INET;
560 dest_addr.sin_addr = stream->multicast_ip;
561 dest_addr.sin_port = htons(stream->multicast_port);
563 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
564 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
568 if (open_input_stream(rtp_c, "") < 0) {
569 http_log("Could not open input stream for stream '%s'\n",
574 /* open each RTP stream */
575 for(stream_index = 0; stream_index < stream->nb_streams;
577 dest_addr.sin_port = htons(stream->multicast_port +
579 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
580 http_log("Could not open output stream '%s/streamid=%d'\n",
581 stream->filename, stream_index);
586 /* change state to send data */
587 rtp_c->state = HTTPSTATE_SEND_DATA;
592 /* main loop of the http server */
593 static int http_server(void)
595 int server_fd = 0, rtsp_server_fd = 0;
596 int ret, delay, delay1;
597 struct pollfd *poll_table, *poll_entry;
598 HTTPContext *c, *c_next;
600 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
601 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
605 if (my_http_addr.sin_port) {
606 server_fd = socket_open_listen(&my_http_addr);
611 if (my_rtsp_addr.sin_port) {
612 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
613 if (rtsp_server_fd < 0)
617 if (!rtsp_server_fd && !server_fd) {
618 http_log("HTTP and RTSP disabled.\n");
622 http_log("FFserver started.\n");
624 start_children(first_feed);
629 poll_entry = poll_table;
631 poll_entry->fd = server_fd;
632 poll_entry->events = POLLIN;
635 if (rtsp_server_fd) {
636 poll_entry->fd = rtsp_server_fd;
637 poll_entry->events = POLLIN;
641 /* wait for events on each HTTP handle */
648 case HTTPSTATE_SEND_HEADER:
649 case RTSPSTATE_SEND_REPLY:
650 case RTSPSTATE_SEND_PACKET:
651 c->poll_entry = poll_entry;
653 poll_entry->events = POLLOUT;
656 case HTTPSTATE_SEND_DATA_HEADER:
657 case HTTPSTATE_SEND_DATA:
658 case HTTPSTATE_SEND_DATA_TRAILER:
659 if (!c->is_packetized) {
660 /* for TCP, we output as much as we can (may need to put a limit) */
661 c->poll_entry = poll_entry;
663 poll_entry->events = POLLOUT;
666 /* when ffserver is doing the timing, we work by
667 looking at which packet need to be sent every
669 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
674 case HTTPSTATE_WAIT_REQUEST:
675 case HTTPSTATE_RECEIVE_DATA:
676 case HTTPSTATE_WAIT_FEED:
677 case RTSPSTATE_WAIT_REQUEST:
678 /* need to catch errors */
679 c->poll_entry = poll_entry;
681 poll_entry->events = POLLIN;/* Maybe this will work */
685 c->poll_entry = NULL;
691 /* wait for an event on one connection. We poll at least every
692 second to handle timeouts */
694 ret = poll(poll_table, poll_entry - poll_table, delay);
695 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
696 ff_neterrno() != AVERROR(EINTR))
700 cur_time = av_gettime() / 1000;
702 if (need_to_start_children) {
703 need_to_start_children = 0;
704 start_children(first_feed);
707 /* now handle the events */
708 for(c = first_http_ctx; c != NULL; c = c_next) {
710 if (handle_connection(c) < 0) {
711 /* close and free the connection */
717 poll_entry = poll_table;
719 /* new HTTP connection request ? */
720 if (poll_entry->revents & POLLIN)
721 new_connection(server_fd, 0);
724 if (rtsp_server_fd) {
725 /* new RTSP connection request ? */
726 if (poll_entry->revents & POLLIN)
727 new_connection(rtsp_server_fd, 1);
732 /* start waiting for a new HTTP/RTSP request */
733 static void start_wait_request(HTTPContext *c, int is_rtsp)
735 c->buffer_ptr = c->buffer;
736 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
739 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
740 c->state = RTSPSTATE_WAIT_REQUEST;
742 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
743 c->state = HTTPSTATE_WAIT_REQUEST;
747 static void http_send_too_busy_reply(int fd)
750 int len = snprintf(buffer, sizeof(buffer),
751 "HTTP/1.0 503 Server too busy\r\n"
752 "Content-type: text/html\r\n"
754 "<html><head><title>Too busy</title></head><body>\r\n"
755 "<p>The server is too busy to serve your request at this time.</p>\r\n"
756 "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
757 "</body></html>\r\n",
758 nb_connections, nb_max_connections);
759 send(fd, buffer, len, 0);
763 static void new_connection(int server_fd, int is_rtsp)
765 struct sockaddr_in from_addr;
767 HTTPContext *c = NULL;
769 len = sizeof(from_addr);
770 fd = accept(server_fd, (struct sockaddr *)&from_addr,
773 http_log("error during accept %s\n", strerror(errno));
776 ff_socket_nonblock(fd, 1);
778 if (nb_connections >= nb_max_connections) {
779 http_send_too_busy_reply(fd);
783 /* add a new connection */
784 c = av_mallocz(sizeof(HTTPContext));
789 c->poll_entry = NULL;
790 c->from_addr = from_addr;
791 c->buffer_size = IOBUFFER_INIT_SIZE;
792 c->buffer = av_malloc(c->buffer_size);
796 c->next = first_http_ctx;
800 start_wait_request(c, is_rtsp);
812 static void close_connection(HTTPContext *c)
814 HTTPContext **cp, *c1;
816 AVFormatContext *ctx;
820 /* remove connection from list */
821 cp = &first_http_ctx;
822 while ((*cp) != NULL) {
830 /* remove references, if any (XXX: do it faster) */
831 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
836 /* remove connection associated resources */
840 /* close each frame parser */
841 for(i=0;i<c->fmt_in->nb_streams;i++) {
842 st = c->fmt_in->streams[i];
843 if (st->codec->codec)
844 avcodec_close(st->codec);
846 av_close_input_file(c->fmt_in);
849 /* free RTP output streams if any */
852 nb_streams = c->stream->nb_streams;
854 for(i=0;i<nb_streams;i++) {
857 av_write_trailer(ctx);
858 av_dict_free(&ctx->metadata);
859 av_free(ctx->streams[0]);
862 h = c->rtp_handles[i];
869 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
872 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
873 av_write_trailer(ctx);
874 av_freep(&c->pb_buffer);
875 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
880 for(i=0; i<ctx->nb_streams; i++)
881 av_free(ctx->streams[i]);
883 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
884 current_bandwidth -= c->stream->bandwidth;
886 /* signal that there is no feed if we are the feeder socket */
887 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
888 c->stream->feed_opened = 0;
892 av_freep(&c->pb_buffer);
893 av_freep(&c->packet_buffer);
899 static int handle_connection(HTTPContext *c)
904 case HTTPSTATE_WAIT_REQUEST:
905 case RTSPSTATE_WAIT_REQUEST:
907 if ((c->timeout - cur_time) < 0)
909 if (c->poll_entry->revents & (POLLERR | POLLHUP))
912 /* no need to read if no events */
913 if (!(c->poll_entry->revents & POLLIN))
917 len = recv(c->fd, c->buffer_ptr, 1, 0);
919 if (ff_neterrno() != AVERROR(EAGAIN) &&
920 ff_neterrno() != AVERROR(EINTR))
922 } else if (len == 0) {
925 /* search for end of request. */
927 c->buffer_ptr += len;
929 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
930 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
931 /* request found : parse it and reply */
932 if (c->state == HTTPSTATE_WAIT_REQUEST) {
933 ret = http_parse_request(c);
935 ret = rtsp_parse_request(c);
939 } else if (ptr >= c->buffer_end) {
940 /* request too long: cannot do anything */
942 } else goto read_loop;
946 case HTTPSTATE_SEND_HEADER:
947 if (c->poll_entry->revents & (POLLERR | POLLHUP))
950 /* no need to write if no events */
951 if (!(c->poll_entry->revents & POLLOUT))
953 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
955 if (ff_neterrno() != AVERROR(EAGAIN) &&
956 ff_neterrno() != AVERROR(EINTR)) {
957 /* error : close connection */
958 av_freep(&c->pb_buffer);
962 c->buffer_ptr += len;
964 c->stream->bytes_served += len;
965 c->data_count += len;
966 if (c->buffer_ptr >= c->buffer_end) {
967 av_freep(&c->pb_buffer);
971 /* all the buffer was sent : synchronize to the incoming stream */
972 c->state = HTTPSTATE_SEND_DATA_HEADER;
973 c->buffer_ptr = c->buffer_end = c->buffer;
978 case HTTPSTATE_SEND_DATA:
979 case HTTPSTATE_SEND_DATA_HEADER:
980 case HTTPSTATE_SEND_DATA_TRAILER:
981 /* for packetized output, we consider we can always write (the
982 input streams sets the speed). It may be better to verify
983 that we do not rely too much on the kernel queues */
984 if (!c->is_packetized) {
985 if (c->poll_entry->revents & (POLLERR | POLLHUP))
988 /* no need to read if no events */
989 if (!(c->poll_entry->revents & POLLOUT))
992 if (http_send_data(c) < 0)
994 /* close connection if trailer sent */
995 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
998 case HTTPSTATE_RECEIVE_DATA:
999 /* no need to read if no events */
1000 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1002 if (!(c->poll_entry->revents & POLLIN))
1004 if (http_receive_data(c) < 0)
1007 case HTTPSTATE_WAIT_FEED:
1008 /* no need to read if no events */
1009 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1012 /* nothing to do, we'll be waken up by incoming feed packets */
1015 case RTSPSTATE_SEND_REPLY:
1016 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1017 av_freep(&c->pb_buffer);
1020 /* no need to write if no events */
1021 if (!(c->poll_entry->revents & POLLOUT))
1023 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1025 if (ff_neterrno() != AVERROR(EAGAIN) &&
1026 ff_neterrno() != AVERROR(EINTR)) {
1027 /* error : close connection */
1028 av_freep(&c->pb_buffer);
1032 c->buffer_ptr += len;
1033 c->data_count += len;
1034 if (c->buffer_ptr >= c->buffer_end) {
1035 /* all the buffer was sent : wait for a new request */
1036 av_freep(&c->pb_buffer);
1037 start_wait_request(c, 1);
1041 case RTSPSTATE_SEND_PACKET:
1042 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1043 av_freep(&c->packet_buffer);
1046 /* no need to write if no events */
1047 if (!(c->poll_entry->revents & POLLOUT))
1049 len = send(c->fd, c->packet_buffer_ptr,
1050 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1052 if (ff_neterrno() != AVERROR(EAGAIN) &&
1053 ff_neterrno() != AVERROR(EINTR)) {
1054 /* error : close connection */
1055 av_freep(&c->packet_buffer);
1059 c->packet_buffer_ptr += len;
1060 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1061 /* all the buffer was sent : wait for a new request */
1062 av_freep(&c->packet_buffer);
1063 c->state = RTSPSTATE_WAIT_REQUEST;
1067 case HTTPSTATE_READY:
1076 static int extract_rates(char *rates, int ratelen, const char *request)
1080 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1081 if (strncasecmp(p, "Pragma:", 7) == 0) {
1082 const char *q = p + 7;
1084 while (*q && *q != '\n' && isspace(*q))
1087 if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1093 memset(rates, 0xff, ratelen);
1096 while (*q && *q != '\n' && *q != ':')
1099 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1103 if (stream_no < ratelen && stream_no >= 0)
1104 rates[stream_no] = rate_no;
1106 while (*q && *q != '\n' && !isspace(*q))
1113 p = strchr(p, '\n');
1123 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1126 int best_bitrate = 100000000;
1129 for (i = 0; i < feed->nb_streams; i++) {
1130 AVCodecContext *feed_codec = feed->streams[i]->codec;
1132 if (feed_codec->codec_id != codec->codec_id ||
1133 feed_codec->sample_rate != codec->sample_rate ||
1134 feed_codec->width != codec->width ||
1135 feed_codec->height != codec->height)
1138 /* Potential stream */
1140 /* We want the fastest stream less than bit_rate, or the slowest
1141 * faster than bit_rate
1144 if (feed_codec->bit_rate <= bit_rate) {
1145 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1146 best_bitrate = feed_codec->bit_rate;
1150 if (feed_codec->bit_rate < best_bitrate) {
1151 best_bitrate = feed_codec->bit_rate;
1160 static int modify_current_stream(HTTPContext *c, char *rates)
1163 FFStream *req = c->stream;
1164 int action_required = 0;
1166 /* Not much we can do for a feed */
1170 for (i = 0; i < req->nb_streams; i++) {
1171 AVCodecContext *codec = req->streams[i]->codec;
1175 c->switch_feed_streams[i] = req->feed_streams[i];
1178 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1181 /* Wants off or slow */
1182 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1184 /* This doesn't work well when it turns off the only stream! */
1185 c->switch_feed_streams[i] = -2;
1186 c->feed_streams[i] = -2;
1191 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1192 action_required = 1;
1195 return action_required;
1198 /* XXX: factorize in utils.c ? */
1199 /* XXX: take care with different space meaning */
1200 static void skip_spaces(const char **pp)
1204 while (*p == ' ' || *p == '\t')
1209 static void get_word(char *buf, int buf_size, const char **pp)
1217 while (!isspace(*p) && *p != '\0') {
1218 if ((q - buf) < buf_size - 1)
1227 static void get_arg(char *buf, int buf_size, const char **pp)
1234 while (isspace(*p)) p++;
1237 if (*p == '\"' || *p == '\'')
1249 if ((q - buf) < buf_size - 1)
1254 if (quote && *p == quote)
1259 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1260 const char *p, const char *filename, int line_num)
1266 get_arg(arg, sizeof(arg), &p);
1267 if (strcasecmp(arg, "allow") == 0)
1268 acl.action = IP_ALLOW;
1269 else if (strcasecmp(arg, "deny") == 0)
1270 acl.action = IP_DENY;
1272 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1273 filename, line_num, arg);
1277 get_arg(arg, sizeof(arg), &p);
1279 if (resolve_host(&acl.first, arg) != 0) {
1280 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1281 filename, line_num, arg);
1284 acl.last = acl.first;
1286 get_arg(arg, sizeof(arg), &p);
1289 if (resolve_host(&acl.last, arg) != 0) {
1290 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1291 filename, line_num, arg);
1297 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1298 IPAddressACL **naclp = 0;
1304 naclp = &stream->acl;
1310 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1311 filename, line_num);
1317 naclp = &(*naclp)->next;
1325 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1330 IPAddressACL *acl = NULL;
1334 f = fopen(stream->dynamic_acl, "r");
1336 perror(stream->dynamic_acl);
1340 acl = av_mallocz(sizeof(IPAddressACL));
1344 if (fgets(line, sizeof(line), f) == NULL)
1350 if (*p == '\0' || *p == '#')
1352 get_arg(cmd, sizeof(cmd), &p);
1354 if (!strcasecmp(cmd, "ACL"))
1355 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1362 static void free_acl_list(IPAddressACL *in_acl)
1364 IPAddressACL *pacl,*pacl2;
1374 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1376 enum IPAddressAction last_action = IP_DENY;
1378 struct in_addr *src = &c->from_addr.sin_addr;
1379 unsigned long src_addr = src->s_addr;
1381 for (acl = in_acl; acl; acl = acl->next) {
1382 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1383 return (acl->action == IP_ALLOW) ? 1 : 0;
1384 last_action = acl->action;
1387 /* Nothing matched, so return not the last action */
1388 return (last_action == IP_DENY) ? 1 : 0;
1391 static int validate_acl(FFStream *stream, HTTPContext *c)
1397 /* if stream->acl is null validate_acl_list will return 1 */
1398 ret = validate_acl_list(stream->acl, c);
1400 if (stream->dynamic_acl[0]) {
1401 acl = parse_dynamic_acl(stream, c);
1403 ret = validate_acl_list(acl, c);
1411 /* compute the real filename of a file by matching it without its
1412 extensions to all the stream filenames */
1413 static void compute_real_filename(char *filename, int max_size)
1420 /* compute filename by matching without the file extensions */
1421 av_strlcpy(file1, filename, sizeof(file1));
1422 p = strrchr(file1, '.');
1425 for(stream = first_stream; stream != NULL; stream = stream->next) {
1426 av_strlcpy(file2, stream->filename, sizeof(file2));
1427 p = strrchr(file2, '.');
1430 if (!strcmp(file1, file2)) {
1431 av_strlcpy(filename, stream->filename, max_size);
1446 /* parse http request and prepare header */
1447 static int http_parse_request(HTTPContext *c)
1450 enum RedirType redir_type;
1452 char info[1024], filename[1024];
1456 const char *mime_type;
1460 char *useragent = 0;
1463 get_word(cmd, sizeof(cmd), (const char **)&p);
1464 av_strlcpy(c->method, cmd, sizeof(c->method));
1466 if (!strcmp(cmd, "GET"))
1468 else if (!strcmp(cmd, "POST"))
1473 get_word(url, sizeof(url), (const char **)&p);
1474 av_strlcpy(c->url, url, sizeof(c->url));
1476 get_word(protocol, sizeof(protocol), (const char **)&p);
1477 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1480 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1483 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1485 /* find the filename and the optional info string in the request */
1486 p = strchr(url, '?');
1488 av_strlcpy(info, p, sizeof(info));
1493 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1495 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1496 if (strncasecmp(p, "User-Agent:", 11) == 0) {
1498 if (*useragent && *useragent != '\n' && isspace(*useragent))
1502 p = strchr(p, '\n');
1509 redir_type = REDIR_NONE;
1510 if (av_match_ext(filename, "asx")) {
1511 redir_type = REDIR_ASX;
1512 filename[strlen(filename)-1] = 'f';
1513 } else if (av_match_ext(filename, "asf") &&
1514 (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1515 /* if this isn't WMP or lookalike, return the redirector file */
1516 redir_type = REDIR_ASF;
1517 } else if (av_match_ext(filename, "rpm,ram")) {
1518 redir_type = REDIR_RAM;
1519 strcpy(filename + strlen(filename)-2, "m");
1520 } else if (av_match_ext(filename, "rtsp")) {
1521 redir_type = REDIR_RTSP;
1522 compute_real_filename(filename, sizeof(filename) - 1);
1523 } else if (av_match_ext(filename, "sdp")) {
1524 redir_type = REDIR_SDP;
1525 compute_real_filename(filename, sizeof(filename) - 1);
1528 // "redirect" / request to index.html
1529 if (!strlen(filename))
1530 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1532 stream = first_stream;
1533 while (stream != NULL) {
1534 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1536 stream = stream->next;
1538 if (stream == NULL) {
1539 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1540 http_log("File '%s' not found\n", url);
1545 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1546 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1548 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1549 c->http_error = 301;
1551 q += snprintf(q, c->buffer_size,
1552 "HTTP/1.0 301 Moved\r\n"
1554 "Content-type: text/html\r\n"
1556 "<html><head><title>Moved</title></head><body>\r\n"
1557 "You should be <a href=\"%s\">redirected</a>.\r\n"
1558 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1559 /* prepare output buffer */
1560 c->buffer_ptr = c->buffer;
1562 c->state = HTTPSTATE_SEND_HEADER;
1566 /* If this is WMP, get the rate information */
1567 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1568 if (modify_current_stream(c, ratebuf)) {
1569 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1570 if (c->switch_feed_streams[i] >= 0)
1571 c->switch_feed_streams[i] = -1;
1576 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1577 current_bandwidth += stream->bandwidth;
1579 /* If already streaming this feed, do not let start another feeder. */
1580 if (stream->feed_opened) {
1581 snprintf(msg, sizeof(msg), "This feed is already being received.");
1582 http_log("Feed '%s' already being received\n", stream->feed_filename);
1586 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1587 c->http_error = 503;
1589 q += snprintf(q, c->buffer_size,
1590 "HTTP/1.0 503 Server too busy\r\n"
1591 "Content-type: text/html\r\n"
1593 "<html><head><title>Too busy</title></head><body>\r\n"
1594 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1595 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1596 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1597 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1598 /* prepare output buffer */
1599 c->buffer_ptr = c->buffer;
1601 c->state = HTTPSTATE_SEND_HEADER;
1605 if (redir_type != REDIR_NONE) {
1608 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1609 if (strncasecmp(p, "Host:", 5) == 0) {
1613 p = strchr(p, '\n');
1624 while (isspace(*hostinfo))
1627 eoh = strchr(hostinfo, '\n');
1629 if (eoh[-1] == '\r')
1632 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1633 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1634 hostbuf[eoh - hostinfo] = 0;
1636 c->http_error = 200;
1638 switch(redir_type) {
1640 q += snprintf(q, c->buffer_size,
1641 "HTTP/1.0 200 ASX Follows\r\n"
1642 "Content-type: video/x-ms-asf\r\n"
1644 "<ASX Version=\"3\">\r\n"
1645 //"<!-- Autogenerated by ffserver -->\r\n"
1646 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1647 "</ASX>\r\n", hostbuf, filename, info);
1650 q += snprintf(q, c->buffer_size,
1651 "HTTP/1.0 200 RAM Follows\r\n"
1652 "Content-type: audio/x-pn-realaudio\r\n"
1654 "# Autogenerated by ffserver\r\n"
1655 "http://%s/%s%s\r\n", hostbuf, filename, info);
1658 q += snprintf(q, c->buffer_size,
1659 "HTTP/1.0 200 ASF Redirect follows\r\n"
1660 "Content-type: video/x-ms-asf\r\n"
1663 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1667 char hostname[256], *p;
1668 /* extract only hostname */
1669 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1670 p = strrchr(hostname, ':');
1673 q += snprintf(q, c->buffer_size,
1674 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1675 /* XXX: incorrect mime type ? */
1676 "Content-type: application/x-rtsp\r\n"
1678 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1684 int sdp_data_size, len;
1685 struct sockaddr_in my_addr;
1687 q += snprintf(q, c->buffer_size,
1688 "HTTP/1.0 200 OK\r\n"
1689 "Content-type: application/sdp\r\n"
1692 len = sizeof(my_addr);
1693 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1695 /* XXX: should use a dynamic buffer */
1696 sdp_data_size = prepare_sdp_description(stream,
1699 if (sdp_data_size > 0) {
1700 memcpy(q, sdp_data, sdp_data_size);
1712 /* prepare output buffer */
1713 c->buffer_ptr = c->buffer;
1715 c->state = HTTPSTATE_SEND_HEADER;
1721 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1725 stream->conns_served++;
1727 /* XXX: add there authenticate and IP match */
1730 /* if post, it means a feed is being sent */
1731 if (!stream->is_feed) {
1732 /* However it might be a status report from WMP! Let us log the
1733 * data as it might come in handy one day. */
1737 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1738 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1742 if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1743 client_id = strtol(p + 18, 0, 10);
1744 p = strchr(p, '\n');
1752 char *eol = strchr(logline, '\n');
1757 if (eol[-1] == '\r')
1759 http_log("%.*s\n", (int) (eol - logline), logline);
1760 c->suppress_log = 1;
1765 http_log("\nGot request:\n%s\n", c->buffer);
1768 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1771 /* Now we have to find the client_id */
1772 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1773 if (wmpc->wmp_client_id == client_id)
1777 if (wmpc && modify_current_stream(wmpc, ratebuf))
1778 wmpc->switch_pending = 1;
1781 snprintf(msg, sizeof(msg), "POST command not handled");
1785 if (http_start_receive_data(c) < 0) {
1786 snprintf(msg, sizeof(msg), "could not open feed");
1790 c->state = HTTPSTATE_RECEIVE_DATA;
1795 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1796 http_log("\nGot request:\n%s\n", c->buffer);
1799 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1802 /* open input stream */
1803 if (open_input_stream(c, info) < 0) {
1804 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1808 /* prepare http header */
1810 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1811 mime_type = c->stream->fmt->mime_type;
1813 mime_type = "application/x-octet-stream";
1814 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1816 /* for asf, we need extra headers */
1817 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1818 /* Need to allocate a client id */
1820 c->wmp_client_id = av_lfg_get(&random_state);
1822 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);
1824 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1825 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1827 /* prepare output buffer */
1829 c->buffer_ptr = c->buffer;
1831 c->state = HTTPSTATE_SEND_HEADER;
1834 c->http_error = 404;
1836 q += snprintf(q, c->buffer_size,
1837 "HTTP/1.0 404 Not Found\r\n"
1838 "Content-type: text/html\r\n"
1841 "<head><title>404 Not Found</title></head>\n"
1844 /* prepare output buffer */
1845 c->buffer_ptr = c->buffer;
1847 c->state = HTTPSTATE_SEND_HEADER;
1851 c->http_error = 200; /* horrible : we use this value to avoid
1852 going to the send data state */
1853 c->state = HTTPSTATE_SEND_HEADER;
1857 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1859 static const char *suffix = " kMGTP";
1862 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1864 avio_printf(pb, "%"PRId64"%c", count, *s);
1867 static void compute_status(HTTPContext *c)
1876 if (avio_open_dyn_buf(&pb) < 0) {
1877 /* XXX: return an error ? */
1878 c->buffer_ptr = c->buffer;
1879 c->buffer_end = c->buffer;
1883 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1884 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1885 avio_printf(pb, "Pragma: no-cache\r\n");
1886 avio_printf(pb, "\r\n");
1888 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1889 if (c->stream->feed_filename[0])
1890 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1891 avio_printf(pb, "</head>\n<body>");
1892 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1894 avio_printf(pb, "<h2>Available Streams</h2>\n");
1895 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1896 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");
1897 stream = first_stream;
1898 while (stream != NULL) {
1899 char sfilename[1024];
1902 if (stream->feed != stream) {
1903 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1904 eosf = sfilename + strlen(sfilename);
1905 if (eosf - sfilename >= 4) {
1906 if (strcmp(eosf - 4, ".asf") == 0)
1907 strcpy(eosf - 4, ".asx");
1908 else if (strcmp(eosf - 3, ".rm") == 0)
1909 strcpy(eosf - 3, ".ram");
1910 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1911 /* generate a sample RTSP director if
1912 unicast. Generate an SDP redirector if
1914 eosf = strrchr(sfilename, '.');
1916 eosf = sfilename + strlen(sfilename);
1917 if (stream->is_multicast)
1918 strcpy(eosf, ".sdp");
1920 strcpy(eosf, ".rtsp");
1924 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1925 sfilename, stream->filename);
1926 avio_printf(pb, "<td align=right> %d <td align=right> ",
1927 stream->conns_served);
1928 fmt_bytecount(pb, stream->bytes_served);
1929 switch(stream->stream_type) {
1930 case STREAM_TYPE_LIVE: {
1931 int audio_bit_rate = 0;
1932 int video_bit_rate = 0;
1933 const char *audio_codec_name = "";
1934 const char *video_codec_name = "";
1935 const char *audio_codec_name_extra = "";
1936 const char *video_codec_name_extra = "";
1938 for(i=0;i<stream->nb_streams;i++) {
1939 AVStream *st = stream->streams[i];
1940 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1941 switch(st->codec->codec_type) {
1942 case AVMEDIA_TYPE_AUDIO:
1943 audio_bit_rate += st->codec->bit_rate;
1945 if (*audio_codec_name)
1946 audio_codec_name_extra = "...";
1947 audio_codec_name = codec->name;
1950 case AVMEDIA_TYPE_VIDEO:
1951 video_bit_rate += st->codec->bit_rate;
1953 if (*video_codec_name)
1954 video_codec_name_extra = "...";
1955 video_codec_name = codec->name;
1958 case AVMEDIA_TYPE_DATA:
1959 video_bit_rate += st->codec->bit_rate;
1965 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",
1968 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1969 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1971 avio_printf(pb, "<td>%s", stream->feed->filename);
1973 avio_printf(pb, "<td>%s", stream->feed_filename);
1974 avio_printf(pb, "\n");
1978 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1982 stream = stream->next;
1984 avio_printf(pb, "</table>\n");
1986 stream = first_stream;
1987 while (stream != NULL) {
1988 if (stream->feed == stream) {
1989 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1991 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1993 #if defined(linux) && !defined(CONFIG_NOCUTILS)
1998 /* This is somewhat linux specific I guess */
1999 snprintf(ps_cmd, sizeof(ps_cmd),
2000 "ps -o \"%%cpu,cputime\" --no-headers %d",
2003 pid_stat = popen(ps_cmd, "r");
2008 if (fscanf(pid_stat, "%10s %64s", cpuperc,
2010 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2018 avio_printf(pb, "<p>");
2020 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");
2022 for (i = 0; i < stream->nb_streams; i++) {
2023 AVStream *st = stream->streams[i];
2024 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2025 const char *type = "unknown";
2026 char parameters[64];
2030 switch(st->codec->codec_type) {
2031 case AVMEDIA_TYPE_AUDIO:
2033 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2035 case AVMEDIA_TYPE_VIDEO:
2037 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2038 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2043 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2044 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2046 avio_printf(pb, "</table>\n");
2049 stream = stream->next;
2052 /* connection status */
2053 avio_printf(pb, "<h2>Connection Status</h2>\n");
2055 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2056 nb_connections, nb_max_connections);
2058 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2059 current_bandwidth, max_bandwidth);
2061 avio_printf(pb, "<table>\n");
2062 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");
2063 c1 = first_http_ctx;
2065 while (c1 != NULL) {
2071 for (j = 0; j < c1->stream->nb_streams; j++) {
2072 if (!c1->stream->feed)
2073 bitrate += c1->stream->streams[j]->codec->bit_rate;
2074 else if (c1->feed_streams[j] >= 0)
2075 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2080 p = inet_ntoa(c1->from_addr.sin_addr);
2081 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2083 c1->stream ? c1->stream->filename : "",
2084 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2087 http_state[c1->state]);
2088 fmt_bytecount(pb, bitrate);
2089 avio_printf(pb, "<td align=right>");
2090 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2091 avio_printf(pb, "<td align=right>");
2092 fmt_bytecount(pb, c1->data_count);
2093 avio_printf(pb, "\n");
2096 avio_printf(pb, "</table>\n");
2101 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2102 avio_printf(pb, "</body>\n</html>\n");
2104 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2105 c->buffer_ptr = c->pb_buffer;
2106 c->buffer_end = c->pb_buffer + len;
2109 /* check if the parser needs to be opened for stream i */
2110 static void open_parser(AVFormatContext *s, int i)
2112 AVStream *st = s->streams[i];
2115 if (!st->codec->codec) {
2116 codec = avcodec_find_decoder(st->codec->codec_id);
2117 if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2118 st->codec->parse_only = 1;
2119 if (avcodec_open(st->codec, codec) < 0)
2120 st->codec->parse_only = 0;
2125 static int open_input_stream(HTTPContext *c, const char *info)
2128 char input_filename[1024];
2130 int buf_size, i, ret;
2133 /* find file name */
2134 if (c->stream->feed) {
2135 strcpy(input_filename, c->stream->feed->feed_filename);
2136 buf_size = FFM_PACKET_SIZE;
2137 /* compute position (absolute time) */
2138 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2139 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2141 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2142 int prebuffer = strtol(buf, 0, 10);
2143 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2145 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2147 strcpy(input_filename, c->stream->feed_filename);
2149 /* compute position (relative time) */
2150 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2151 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2156 if (input_filename[0] == '\0')
2160 if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
2161 buf_size, c->stream->ap_in)) < 0) {
2162 http_log("could not open %s: %d\n", input_filename, ret);
2165 s->flags |= AVFMT_FLAG_GENPTS;
2167 if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2168 http_log("Could not find stream info '%s'\n", input_filename);
2169 av_close_input_file(s);
2173 /* open each parser */
2174 for(i=0;i<s->nb_streams;i++)
2177 /* choose stream as clock source (we favorize video stream if
2178 present) for packet sending */
2179 c->pts_stream_index = 0;
2180 for(i=0;i<c->stream->nb_streams;i++) {
2181 if (c->pts_stream_index == 0 &&
2182 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2183 c->pts_stream_index = i;
2187 if (c->fmt_in->iformat->read_seek)
2188 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2189 /* set the start time (needed for maxtime and RTP packet timing) */
2190 c->start_time = cur_time;
2191 c->first_pts = AV_NOPTS_VALUE;
2195 /* return the server clock (in us) */
2196 static int64_t get_server_clock(HTTPContext *c)
2198 /* compute current pts value from system time */
2199 return (cur_time - c->start_time) * 1000;
2202 /* return the estimated time at which the current packet must be sent
2204 static int64_t get_packet_send_clock(HTTPContext *c)
2206 int bytes_left, bytes_sent, frame_bytes;
2208 frame_bytes = c->cur_frame_bytes;
2209 if (frame_bytes <= 0)
2212 bytes_left = c->buffer_end - c->buffer_ptr;
2213 bytes_sent = frame_bytes - bytes_left;
2214 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2219 static int http_prepare_data(HTTPContext *c)
2222 AVFormatContext *ctx;
2224 av_freep(&c->pb_buffer);
2226 case HTTPSTATE_SEND_DATA_HEADER:
2227 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2228 av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2229 av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2230 av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2231 av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2233 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2235 for(i=0;i<c->stream->nb_streams;i++) {
2237 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2238 /* if file or feed, then just take streams from FFStream struct */
2239 if (!c->stream->feed ||
2240 c->stream->feed == c->stream)
2241 src = c->stream->streams[i];
2243 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2245 *(c->fmt_ctx.streams[i]) = *src;
2246 c->fmt_ctx.streams[i]->priv_data = 0;
2247 c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2248 AVStream, not in codec */
2250 /* set output format parameters */
2251 c->fmt_ctx.oformat = c->stream->fmt;
2252 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2254 c->got_key_frame = 0;
2256 /* prepare header and save header data in a stream */
2257 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2258 /* XXX: potential leak */
2261 c->fmt_ctx.pb->seekable = 0;
2264 * HACK to avoid mpeg ps muxer to spit many underflow errors
2265 * Default value from FFmpeg
2266 * Try to set it use configuration option
2268 c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
2269 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2271 av_set_parameters(&c->fmt_ctx, NULL);
2272 if (av_write_header(&c->fmt_ctx) < 0) {
2273 http_log("Error writing output header\n");
2276 av_dict_free(&c->fmt_ctx.metadata);
2278 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2279 c->buffer_ptr = c->pb_buffer;
2280 c->buffer_end = c->pb_buffer + len;
2282 c->state = HTTPSTATE_SEND_DATA;
2283 c->last_packet_sent = 0;
2285 case HTTPSTATE_SEND_DATA:
2286 /* find a new packet */
2287 /* read a packet from the input stream */
2288 if (c->stream->feed)
2289 ffm_set_write_index(c->fmt_in,
2290 c->stream->feed->feed_write_index,
2291 c->stream->feed->feed_size);
2293 if (c->stream->max_time &&
2294 c->stream->max_time + c->start_time - cur_time < 0)
2295 /* We have timed out */
2296 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2300 ret = av_read_frame(c->fmt_in, &pkt);
2302 if (c->stream->feed) {
2303 /* if coming from feed, it means we reached the end of the
2304 ffm file, so must wait for more data */
2305 c->state = HTTPSTATE_WAIT_FEED;
2306 return 1; /* state changed */
2307 } else if (ret == AVERROR(EAGAIN)) {
2308 /* input not ready, come back later */
2311 if (c->stream->loop) {
2312 av_close_input_file(c->fmt_in);
2314 if (open_input_stream(c, "") < 0)
2319 /* must send trailer now because eof or error */
2320 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2324 int source_index = pkt.stream_index;
2325 /* update first pts if needed */
2326 if (c->first_pts == AV_NOPTS_VALUE) {
2327 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2328 c->start_time = cur_time;
2330 /* send it to the appropriate stream */
2331 if (c->stream->feed) {
2332 /* if coming from a feed, select the right stream */
2333 if (c->switch_pending) {
2334 c->switch_pending = 0;
2335 for(i=0;i<c->stream->nb_streams;i++) {
2336 if (c->switch_feed_streams[i] == pkt.stream_index)
2337 if (pkt.flags & AV_PKT_FLAG_KEY)
2338 c->switch_feed_streams[i] = -1;
2339 if (c->switch_feed_streams[i] >= 0)
2340 c->switch_pending = 1;
2343 for(i=0;i<c->stream->nb_streams;i++) {
2344 if (c->stream->feed_streams[i] == pkt.stream_index) {
2345 AVStream *st = c->fmt_in->streams[source_index];
2346 pkt.stream_index = i;
2347 if (pkt.flags & AV_PKT_FLAG_KEY &&
2348 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2349 c->stream->nb_streams == 1))
2350 c->got_key_frame = 1;
2351 if (!c->stream->send_on_key || c->got_key_frame)
2356 AVCodecContext *codec;
2357 AVStream *ist, *ost;
2359 ist = c->fmt_in->streams[source_index];
2360 /* specific handling for RTP: we use several
2361 output stream (one for each RTP
2362 connection). XXX: need more abstract handling */
2363 if (c->is_packetized) {
2364 /* compute send time and duration */
2365 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2366 c->cur_pts -= c->first_pts;
2367 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2368 /* find RTP context */
2369 c->packet_stream_index = pkt.stream_index;
2370 ctx = c->rtp_ctx[c->packet_stream_index];
2372 av_free_packet(&pkt);
2375 codec = ctx->streams[0]->codec;
2376 /* only one stream per RTP connection */
2377 pkt.stream_index = 0;
2381 codec = ctx->streams[pkt.stream_index]->codec;
2384 if (c->is_packetized) {
2385 int max_packet_size;
2386 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2387 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2389 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2390 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2392 ret = avio_open_dyn_buf(&ctx->pb);
2395 /* XXX: potential leak */
2398 ost = ctx->streams[pkt.stream_index];
2400 ctx->pb->seekable = 0;
2401 if (pkt.dts != AV_NOPTS_VALUE)
2402 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2403 if (pkt.pts != AV_NOPTS_VALUE)
2404 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2405 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2406 if (av_write_frame(ctx, &pkt) < 0) {
2407 http_log("Error writing frame to output\n");
2408 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2411 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2412 c->cur_frame_bytes = len;
2413 c->buffer_ptr = c->pb_buffer;
2414 c->buffer_end = c->pb_buffer + len;
2416 codec->frame_number++;
2418 av_free_packet(&pkt);
2422 av_free_packet(&pkt);
2427 case HTTPSTATE_SEND_DATA_TRAILER:
2428 /* last packet test ? */
2429 if (c->last_packet_sent || c->is_packetized)
2432 /* prepare header */
2433 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2434 /* XXX: potential leak */
2437 c->fmt_ctx.pb->seekable = 0;
2438 av_write_trailer(ctx);
2439 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2440 c->buffer_ptr = c->pb_buffer;
2441 c->buffer_end = c->pb_buffer + len;
2443 c->last_packet_sent = 1;
2449 /* should convert the format at the same time */
2450 /* send data starting at c->buffer_ptr to the output connection
2451 (either UDP or TCP connection) */
2452 static int http_send_data(HTTPContext *c)
2457 if (c->buffer_ptr >= c->buffer_end) {
2458 ret = http_prepare_data(c);
2462 /* state change requested */
2465 if (c->is_packetized) {
2466 /* RTP data output */
2467 len = c->buffer_end - c->buffer_ptr;
2469 /* fail safe - should never happen */
2471 c->buffer_ptr = c->buffer_end;
2474 len = (c->buffer_ptr[0] << 24) |
2475 (c->buffer_ptr[1] << 16) |
2476 (c->buffer_ptr[2] << 8) |
2478 if (len > (c->buffer_end - c->buffer_ptr))
2480 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2481 /* nothing to send yet: we can wait */
2485 c->data_count += len;
2486 update_datarate(&c->datarate, c->data_count);
2488 c->stream->bytes_served += len;
2490 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2491 /* RTP packets are sent inside the RTSP TCP connection */
2493 int interleaved_index, size;
2495 HTTPContext *rtsp_c;
2498 /* if no RTSP connection left, error */
2501 /* if already sending something, then wait. */
2502 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2504 if (avio_open_dyn_buf(&pb) < 0)
2506 interleaved_index = c->packet_stream_index * 2;
2507 /* RTCP packets are sent at odd indexes */
2508 if (c->buffer_ptr[1] == 200)
2509 interleaved_index++;
2510 /* write RTSP TCP header */
2512 header[1] = interleaved_index;
2513 header[2] = len >> 8;
2515 avio_write(pb, header, 4);
2516 /* write RTP packet data */
2518 avio_write(pb, c->buffer_ptr, len);
2519 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2520 /* prepare asynchronous TCP sending */
2521 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2522 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2523 c->buffer_ptr += len;
2525 /* send everything we can NOW */
2526 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2527 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2529 rtsp_c->packet_buffer_ptr += len;
2530 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2531 /* if we could not send all the data, we will
2532 send it later, so a new state is needed to
2533 "lock" the RTSP TCP connection */
2534 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2537 /* all data has been sent */
2538 av_freep(&c->packet_buffer);
2540 /* send RTP packet directly in UDP */
2542 url_write(c->rtp_handles[c->packet_stream_index],
2543 c->buffer_ptr, len);
2544 c->buffer_ptr += len;
2545 /* here we continue as we can send several packets per 10 ms slot */
2548 /* TCP data output */
2549 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2551 if (ff_neterrno() != AVERROR(EAGAIN) &&
2552 ff_neterrno() != AVERROR(EINTR))
2553 /* error : close connection */
2558 c->buffer_ptr += len;
2560 c->data_count += len;
2561 update_datarate(&c->datarate, c->data_count);
2563 c->stream->bytes_served += len;
2571 static int http_start_receive_data(HTTPContext *c)
2575 if (c->stream->feed_opened)
2578 /* Don't permit writing to this one */
2579 if (c->stream->readonly)
2583 fd = open(c->stream->feed_filename, O_RDWR);
2585 http_log("Error opening feeder file: %s\n", strerror(errno));
2590 if (c->stream->truncate) {
2591 /* truncate feed file */
2592 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2593 ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2594 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2596 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2597 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2602 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2603 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2604 lseek(fd, 0, SEEK_SET);
2606 /* init buffer input */
2607 c->buffer_ptr = c->buffer;
2608 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2609 c->stream->feed_opened = 1;
2610 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2614 static int http_receive_data(HTTPContext *c)
2617 int len, loop_run = 0;
2619 while (c->chunked_encoding && !c->chunk_size &&
2620 c->buffer_end > c->buffer_ptr) {
2621 /* read chunk header, if present */
2622 len = recv(c->fd, c->buffer_ptr, 1, 0);
2625 if (ff_neterrno() != AVERROR(EAGAIN) &&
2626 ff_neterrno() != AVERROR(EINTR))
2627 /* error : close connection */
2630 } else if (len == 0) {
2631 /* end of connection : close it */
2633 } else if (c->buffer_ptr - c->buffer >= 2 &&
2634 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2635 c->chunk_size = strtol(c->buffer, 0, 16);
2636 if (c->chunk_size == 0) // end of stream
2638 c->buffer_ptr = c->buffer;
2640 } else if (++loop_run > 10) {
2641 /* no chunk header, abort */
2648 if (c->buffer_end > c->buffer_ptr) {
2649 len = recv(c->fd, c->buffer_ptr,
2650 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2652 if (ff_neterrno() != AVERROR(EAGAIN) &&
2653 ff_neterrno() != AVERROR(EINTR))
2654 /* error : close connection */
2656 } else if (len == 0)
2657 /* end of connection : close it */
2660 c->chunk_size -= len;
2661 c->buffer_ptr += len;
2662 c->data_count += len;
2663 update_datarate(&c->datarate, c->data_count);
2667 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2668 if (c->buffer[0] != 'f' ||
2669 c->buffer[1] != 'm') {
2670 http_log("Feed stream has become desynchronized -- disconnecting\n");
2675 if (c->buffer_ptr >= c->buffer_end) {
2676 FFStream *feed = c->stream;
2677 /* a packet has been received : write it in the store, except
2679 if (c->data_count > FFM_PACKET_SIZE) {
2681 // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2682 /* XXX: use llseek or url_seek */
2683 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2684 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2685 http_log("Error writing to feed file: %s\n", strerror(errno));
2689 feed->feed_write_index += FFM_PACKET_SIZE;
2690 /* update file size */
2691 if (feed->feed_write_index > c->stream->feed_size)
2692 feed->feed_size = feed->feed_write_index;
2694 /* handle wrap around if max file size reached */
2695 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2696 feed->feed_write_index = FFM_PACKET_SIZE;
2699 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2700 http_log("Error writing index to feed file: %s\n", strerror(errno));
2704 /* wake up any waiting connections */
2705 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2706 if (c1->state == HTTPSTATE_WAIT_FEED &&
2707 c1->stream->feed == c->stream->feed)
2708 c1->state = HTTPSTATE_SEND_DATA;
2711 /* We have a header in our hands that contains useful data */
2712 AVFormatContext *s = NULL;
2714 AVInputFormat *fmt_in;
2717 /* use feed output format name to find corresponding input format */
2718 fmt_in = av_find_input_format(feed->fmt->name);
2722 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2723 0, NULL, NULL, NULL, NULL);
2726 if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2731 /* Now we have the actual streams */
2732 if (s->nb_streams != feed->nb_streams) {
2733 av_close_input_stream(s);
2735 http_log("Feed '%s' stream number does not match registered feed\n",
2736 c->stream->feed_filename);
2740 for (i = 0; i < s->nb_streams; i++) {
2741 AVStream *fst = feed->streams[i];
2742 AVStream *st = s->streams[i];
2743 avcodec_copy_context(fst->codec, st->codec);
2746 av_close_input_stream(s);
2749 c->buffer_ptr = c->buffer;
2754 c->stream->feed_opened = 0;
2756 /* wake up any waiting connections to stop waiting for feed */
2757 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2758 if (c1->state == HTTPSTATE_WAIT_FEED &&
2759 c1->stream->feed == c->stream->feed)
2760 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2765 /********************************************************************/
2768 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2775 switch(error_number) {
2776 case RTSP_STATUS_OK:
2779 case RTSP_STATUS_METHOD:
2780 str = "Method Not Allowed";
2782 case RTSP_STATUS_BANDWIDTH:
2783 str = "Not Enough Bandwidth";
2785 case RTSP_STATUS_SESSION:
2786 str = "Session Not Found";
2788 case RTSP_STATUS_STATE:
2789 str = "Method Not Valid in This State";
2791 case RTSP_STATUS_AGGREGATE:
2792 str = "Aggregate operation not allowed";
2794 case RTSP_STATUS_ONLY_AGGREGATE:
2795 str = "Only aggregate operation allowed";
2797 case RTSP_STATUS_TRANSPORT:
2798 str = "Unsupported transport";
2800 case RTSP_STATUS_INTERNAL:
2801 str = "Internal Server Error";
2803 case RTSP_STATUS_SERVICE:
2804 str = "Service Unavailable";
2806 case RTSP_STATUS_VERSION:
2807 str = "RTSP Version not supported";
2810 str = "Unknown Error";
2814 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2815 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2817 /* output GMT time */
2820 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2821 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2824 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2826 rtsp_reply_header(c, error_number);
2827 avio_printf(c->pb, "\r\n");
2830 static int rtsp_parse_request(HTTPContext *c)
2832 const char *p, *p1, *p2;
2838 RTSPMessageHeader header1, *header = &header1;
2840 c->buffer_ptr[0] = '\0';
2843 get_word(cmd, sizeof(cmd), &p);
2844 get_word(url, sizeof(url), &p);
2845 get_word(protocol, sizeof(protocol), &p);
2847 av_strlcpy(c->method, cmd, sizeof(c->method));
2848 av_strlcpy(c->url, url, sizeof(c->url));
2849 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2851 if (avio_open_dyn_buf(&c->pb) < 0) {
2852 /* XXX: cannot do more */
2853 c->pb = NULL; /* safety */
2857 /* check version name */
2858 if (strcmp(protocol, "RTSP/1.0") != 0) {
2859 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2863 /* parse each header line */
2864 memset(header, 0, sizeof(*header));
2865 /* skip to next line */
2866 while (*p != '\n' && *p != '\0')
2870 while (*p != '\0') {
2871 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2875 if (p2 > p && p2[-1] == '\r')
2877 /* skip empty line */
2881 if (len > sizeof(line) - 1)
2882 len = sizeof(line) - 1;
2883 memcpy(line, p, len);
2885 ff_rtsp_parse_line(header, line, NULL, NULL);
2889 /* handle sequence number */
2890 c->seq = header->seq;
2892 if (!strcmp(cmd, "DESCRIBE"))
2893 rtsp_cmd_describe(c, url);
2894 else if (!strcmp(cmd, "OPTIONS"))
2895 rtsp_cmd_options(c, url);
2896 else if (!strcmp(cmd, "SETUP"))
2897 rtsp_cmd_setup(c, url, header);
2898 else if (!strcmp(cmd, "PLAY"))
2899 rtsp_cmd_play(c, url, header);
2900 else if (!strcmp(cmd, "PAUSE"))
2901 rtsp_cmd_pause(c, url, header);
2902 else if (!strcmp(cmd, "TEARDOWN"))
2903 rtsp_cmd_teardown(c, url, header);
2905 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2908 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2909 c->pb = NULL; /* safety */
2911 /* XXX: cannot do more */
2914 c->buffer_ptr = c->pb_buffer;
2915 c->buffer_end = c->pb_buffer + len;
2916 c->state = RTSPSTATE_SEND_REPLY;
2920 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2921 struct in_addr my_ip)
2923 AVFormatContext *avc;
2924 AVStream *avs = NULL;
2927 avc = avformat_alloc_context();
2931 av_dict_set(&avc->metadata, "title",
2932 stream->title[0] ? stream->title : "No Title", 0);
2933 avc->nb_streams = stream->nb_streams;
2934 if (stream->is_multicast) {
2935 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2936 inet_ntoa(stream->multicast_ip),
2937 stream->multicast_port, stream->multicast_ttl);
2939 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2942 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2943 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2945 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2946 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2949 for(i = 0; i < stream->nb_streams; i++) {
2950 avc->streams[i] = &avs[i];
2951 avc->streams[i]->codec = stream->streams[i]->codec;
2953 *pbuffer = av_mallocz(2048);
2954 av_sdp_create(&avc, 1, *pbuffer, 2048);
2957 av_free(avc->streams);
2958 av_dict_free(&avc->metadata);
2962 return strlen(*pbuffer);
2965 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2967 // rtsp_reply_header(c, RTSP_STATUS_OK);
2968 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2969 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2970 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2971 avio_printf(c->pb, "\r\n");
2974 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2980 int content_length, len;
2981 struct sockaddr_in my_addr;
2983 /* find which url is asked */
2984 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2989 for(stream = first_stream; stream != NULL; stream = stream->next) {
2990 if (!stream->is_feed &&
2991 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2992 !strcmp(path, stream->filename)) {
2996 /* no stream found */
2997 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3001 /* prepare the media description in sdp format */
3003 /* get the host IP */
3004 len = sizeof(my_addr);
3005 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3006 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3007 if (content_length < 0) {
3008 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3011 rtsp_reply_header(c, RTSP_STATUS_OK);
3012 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3013 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3014 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3015 avio_printf(c->pb, "\r\n");
3016 avio_write(c->pb, content, content_length);
3020 static HTTPContext *find_rtp_session(const char *session_id)
3024 if (session_id[0] == '\0')
3027 for(c = first_http_ctx; c != NULL; c = c->next) {
3028 if (!strcmp(c->session_id, session_id))
3034 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3036 RTSPTransportField *th;
3039 for(i=0;i<h->nb_transports;i++) {
3040 th = &h->transports[i];
3041 if (th->lower_transport == lower_transport)
3047 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3048 RTSPMessageHeader *h)
3051 int stream_index, rtp_port, rtcp_port;
3056 RTSPTransportField *th;
3057 struct sockaddr_in dest_addr;
3058 RTSPActionServerSetup setup;
3060 /* find which url is asked */
3061 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3066 /* now check each stream */
3067 for(stream = first_stream; stream != NULL; stream = stream->next) {
3068 if (!stream->is_feed &&
3069 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3070 /* accept aggregate filenames only if single stream */
3071 if (!strcmp(path, stream->filename)) {
3072 if (stream->nb_streams != 1) {
3073 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3080 for(stream_index = 0; stream_index < stream->nb_streams;
3082 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3083 stream->filename, stream_index);
3084 if (!strcmp(path, buf))
3089 /* no stream found */
3090 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3094 /* generate session id if needed */
3095 if (h->session_id[0] == '\0')
3096 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3097 av_lfg_get(&random_state), av_lfg_get(&random_state));
3099 /* find rtp session, and create it if none found */
3100 rtp_c = find_rtp_session(h->session_id);
3102 /* always prefer UDP */
3103 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3105 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3107 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3112 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3113 th->lower_transport);
3115 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3119 /* open input stream */
3120 if (open_input_stream(rtp_c, "") < 0) {
3121 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3126 /* test if stream is OK (test needed because several SETUP needs
3127 to be done for a given file) */
3128 if (rtp_c->stream != stream) {
3129 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3133 /* test if stream is already set up */
3134 if (rtp_c->rtp_ctx[stream_index]) {
3135 rtsp_reply_error(c, RTSP_STATUS_STATE);
3139 /* check transport */
3140 th = find_transport(h, rtp_c->rtp_protocol);
3141 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3142 th->client_port_min <= 0)) {
3143 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3147 /* setup default options */
3148 setup.transport_option[0] = '\0';
3149 dest_addr = rtp_c->from_addr;
3150 dest_addr.sin_port = htons(th->client_port_min);
3153 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3154 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3158 /* now everything is OK, so we can send the connection parameters */
3159 rtsp_reply_header(c, RTSP_STATUS_OK);
3161 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3163 switch(rtp_c->rtp_protocol) {
3164 case RTSP_LOWER_TRANSPORT_UDP:
3165 rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3166 rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3167 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3168 "client_port=%d-%d;server_port=%d-%d",
3169 th->client_port_min, th->client_port_max,
3170 rtp_port, rtcp_port);
3172 case RTSP_LOWER_TRANSPORT_TCP:
3173 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3174 stream_index * 2, stream_index * 2 + 1);
3179 if (setup.transport_option[0] != '\0')
3180 avio_printf(c->pb, ";%s", setup.transport_option);
3181 avio_printf(c->pb, "\r\n");
3184 avio_printf(c->pb, "\r\n");
3188 /* find an rtp connection by using the session ID. Check consistency
3190 static HTTPContext *find_rtp_session_with_url(const char *url,
3191 const char *session_id)
3199 rtp_c = find_rtp_session(session_id);
3203 /* find which url is asked */
3204 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3208 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3209 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3210 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3211 rtp_c->stream->filename, s);
3212 if(!strncmp(path, buf, sizeof(buf))) {
3213 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3218 if (len > 0 && path[len - 1] == '/' &&
3219 !strncmp(path, rtp_c->stream->filename, len - 1))
3224 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3228 rtp_c = find_rtp_session_with_url(url, h->session_id);
3230 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3234 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3235 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3236 rtp_c->state != HTTPSTATE_READY) {
3237 rtsp_reply_error(c, RTSP_STATUS_STATE);
3241 rtp_c->state = HTTPSTATE_SEND_DATA;
3243 /* now everything is OK, so we can send the connection parameters */
3244 rtsp_reply_header(c, RTSP_STATUS_OK);
3246 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3247 avio_printf(c->pb, "\r\n");
3250 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3254 rtp_c = find_rtp_session_with_url(url, h->session_id);
3256 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3260 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3261 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3262 rtsp_reply_error(c, RTSP_STATUS_STATE);
3266 rtp_c->state = HTTPSTATE_READY;
3267 rtp_c->first_pts = AV_NOPTS_VALUE;
3268 /* now everything is OK, so we can send the connection parameters */
3269 rtsp_reply_header(c, RTSP_STATUS_OK);
3271 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3272 avio_printf(c->pb, "\r\n");
3275 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3279 rtp_c = find_rtp_session_with_url(url, h->session_id);
3281 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3285 /* now everything is OK, so we can send the connection parameters */
3286 rtsp_reply_header(c, RTSP_STATUS_OK);
3288 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3289 avio_printf(c->pb, "\r\n");
3291 /* abort the session */
3292 close_connection(rtp_c);
3296 /********************************************************************/
3299 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3300 FFStream *stream, const char *session_id,
3301 enum RTSPLowerTransport rtp_protocol)
3303 HTTPContext *c = NULL;
3304 const char *proto_str;
3306 /* XXX: should output a warning page when coming
3307 close to the connection limit */
3308 if (nb_connections >= nb_max_connections)
3311 /* add a new connection */
3312 c = av_mallocz(sizeof(HTTPContext));
3317 c->poll_entry = NULL;
3318 c->from_addr = *from_addr;
3319 c->buffer_size = IOBUFFER_INIT_SIZE;
3320 c->buffer = av_malloc(c->buffer_size);
3325 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3326 c->state = HTTPSTATE_READY;
3327 c->is_packetized = 1;
3328 c->rtp_protocol = rtp_protocol;
3330 /* protocol is shown in statistics */
3331 switch(c->rtp_protocol) {
3332 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3333 proto_str = "MCAST";
3335 case RTSP_LOWER_TRANSPORT_UDP:
3338 case RTSP_LOWER_TRANSPORT_TCP:
3345 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3346 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3348 current_bandwidth += stream->bandwidth;
3350 c->next = first_http_ctx;
3362 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3363 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3365 static int rtp_new_av_stream(HTTPContext *c,
3366 int stream_index, struct sockaddr_in *dest_addr,
3367 HTTPContext *rtsp_c)
3369 AVFormatContext *ctx;
3372 URLContext *h = NULL;
3374 int max_packet_size;
3376 /* now we can open the relevant output stream */
3377 ctx = avformat_alloc_context();
3380 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3382 st = av_mallocz(sizeof(AVStream));
3385 ctx->nb_streams = 1;
3386 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3389 ctx->streams[0] = st;
3391 if (!c->stream->feed ||
3392 c->stream->feed == c->stream)
3393 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3396 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3398 st->priv_data = NULL;
3400 /* build destination RTP address */
3401 ipaddr = inet_ntoa(dest_addr->sin_addr);
3403 switch(c->rtp_protocol) {
3404 case RTSP_LOWER_TRANSPORT_UDP:
3405 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3408 /* XXX: also pass as parameter to function ? */
3409 if (c->stream->is_multicast) {
3411 ttl = c->stream->multicast_ttl;
3414 snprintf(ctx->filename, sizeof(ctx->filename),
3415 "rtp://%s:%d?multicast=1&ttl=%d",
3416 ipaddr, ntohs(dest_addr->sin_port), ttl);
3418 snprintf(ctx->filename, sizeof(ctx->filename),
3419 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3422 if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
3424 c->rtp_handles[stream_index] = h;
3425 max_packet_size = url_get_max_packet_size(h);
3427 case RTSP_LOWER_TRANSPORT_TCP:
3430 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3436 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3437 ipaddr, ntohs(dest_addr->sin_port),
3438 c->stream->filename, stream_index, c->protocol);
3440 /* normally, no packets should be output here, but the packet size may be checked */
3441 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3442 /* XXX: close stream */
3445 av_set_parameters(ctx, NULL);
3446 if (av_write_header(ctx) < 0) {
3453 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3456 c->rtp_ctx[stream_index] = ctx;
3460 /********************************************************************/
3461 /* ffserver initialization */
3463 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3467 fst = av_mallocz(sizeof(AVStream));
3471 fst->codec= avcodec_alloc_context();
3472 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3473 if (codec->extradata_size) {
3474 fst->codec->extradata = av_malloc(codec->extradata_size);
3475 memcpy(fst->codec->extradata, codec->extradata,
3476 codec->extradata_size);
3479 /* live streams must use the actual feed's codec since it may be
3480 * updated later to carry extradata needed by the streams.
3484 fst->priv_data = av_mallocz(sizeof(FeedData));
3485 fst->index = stream->nb_streams;
3486 av_set_pts_info(fst, 33, 1, 90000);
3487 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3488 stream->streams[stream->nb_streams++] = fst;
3492 /* return the stream number in the feed */
3493 static int add_av_stream(FFStream *feed, AVStream *st)
3496 AVCodecContext *av, *av1;
3500 for(i=0;i<feed->nb_streams;i++) {
3501 st = feed->streams[i];
3503 if (av1->codec_id == av->codec_id &&
3504 av1->codec_type == av->codec_type &&
3505 av1->bit_rate == av->bit_rate) {
3507 switch(av->codec_type) {
3508 case AVMEDIA_TYPE_AUDIO:
3509 if (av1->channels == av->channels &&
3510 av1->sample_rate == av->sample_rate)
3513 case AVMEDIA_TYPE_VIDEO:
3514 if (av1->width == av->width &&
3515 av1->height == av->height &&
3516 av1->time_base.den == av->time_base.den &&
3517 av1->time_base.num == av->time_base.num &&
3518 av1->gop_size == av->gop_size)
3527 fst = add_av_stream1(feed, av, 0);
3530 return feed->nb_streams - 1;
3535 static void remove_stream(FFStream *stream)
3539 while (*ps != NULL) {
3547 /* specific mpeg4 handling : we extract the raw parameters */
3548 static void extract_mpeg4_header(AVFormatContext *infile)
3550 int mpeg4_count, i, size;
3556 for(i=0;i<infile->nb_streams;i++) {
3557 st = infile->streams[i];
3558 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3559 st->codec->extradata_size == 0) {
3566 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3567 while (mpeg4_count > 0) {
3568 if (av_read_packet(infile, &pkt) < 0)
3570 st = infile->streams[pkt.stream_index];
3571 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3572 st->codec->extradata_size == 0) {
3573 av_freep(&st->codec->extradata);
3574 /* fill extradata with the header */
3575 /* XXX: we make hard suppositions here ! */
3577 while (p < pkt.data + pkt.size - 4) {
3578 /* stop when vop header is found */
3579 if (p[0] == 0x00 && p[1] == 0x00 &&
3580 p[2] == 0x01 && p[3] == 0xb6) {
3581 size = p - pkt.data;
3582 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3583 st->codec->extradata = av_malloc(size);
3584 st->codec->extradata_size = size;
3585 memcpy(st->codec->extradata, pkt.data, size);
3592 av_free_packet(&pkt);
3596 /* compute the needed AVStream for each file */
3597 static void build_file_streams(void)
3599 FFStream *stream, *stream_next;
3600 AVFormatContext *infile;
3603 /* gather all streams */
3604 for(stream = first_stream; stream != NULL; stream = stream_next) {
3605 stream_next = stream->next;
3606 if (stream->stream_type == STREAM_TYPE_LIVE &&
3608 /* the stream comes from a file */
3609 /* try to open the file */
3611 stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3612 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3613 /* specific case : if transport stream output to RTP,
3614 we use a raw transport stream reader */
3615 stream->ap_in->mpeg2ts_raw = 1;
3616 stream->ap_in->mpeg2ts_compute_pcr = 1;
3619 http_log("Opening file '%s'\n", stream->feed_filename);
3620 if ((ret = av_open_input_file(&infile, stream->feed_filename,
3621 stream->ifmt, 0, stream->ap_in)) < 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 (av_find_stream_info(infile) < 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 /* we handle a stream coming from a feed */
3658 for(i=0;i<stream->nb_streams;i++)
3659 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3664 /* gather all streams */
3665 for(stream = first_stream; stream != NULL; stream = stream->next) {
3666 feed = stream->feed;
3668 if (stream->is_feed) {
3669 for(i=0;i<stream->nb_streams;i++)
3670 stream->feed_streams[i] = i;
3675 /* create feed files if needed */
3676 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3679 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3680 /* See if it matches */
3684 if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3685 /* Now see if it matches */
3686 if (s->nb_streams == feed->nb_streams) {
3688 for(i=0;i<s->nb_streams;i++) {
3690 sf = feed->streams[i];
3693 if (sf->index != ss->index ||
3695 http_log("Index & Id do not match for stream %d (%s)\n",
3696 i, feed->feed_filename);
3699 AVCodecContext *ccf, *ccs;
3703 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3705 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3706 http_log("Codecs do not match for stream %d\n", i);
3708 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3709 http_log("Codec bitrates do not match for stream %d\n", i);
3711 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3712 if (CHECK_CODEC(time_base.den) ||
3713 CHECK_CODEC(time_base.num) ||
3714 CHECK_CODEC(width) ||
3715 CHECK_CODEC(height)) {
3716 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3719 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3720 if (CHECK_CODEC(sample_rate) ||
3721 CHECK_CODEC(channels) ||
3722 CHECK_CODEC(frame_size)) {
3723 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3727 http_log("Unknown codec type\n");
3735 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3736 feed->feed_filename, s->nb_streams, feed->nb_streams);
3738 av_close_input_file(s);
3740 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3741 feed->feed_filename);
3744 if (feed->readonly) {
3745 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3746 feed->feed_filename);
3749 unlink(feed->feed_filename);
3752 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3753 AVFormatContext s1 = {0}, *s = &s1;
3755 if (feed->readonly) {
3756 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3757 feed->feed_filename);
3761 /* only write the header of the ffm file */
3762 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3763 http_log("Could not open output feed file '%s'\n",
3764 feed->feed_filename);
3767 s->oformat = feed->fmt;
3768 s->nb_streams = feed->nb_streams;
3769 s->streams = feed->streams;
3770 av_set_parameters(s, NULL);
3771 if (av_write_header(s) < 0) {
3772 http_log("Container doesn't supports the required parameters\n");
3775 /* XXX: need better api */
3776 av_freep(&s->priv_data);
3779 /* get feed size and write index */
3780 fd = open(feed->feed_filename, O_RDONLY);
3782 http_log("Could not open output feed file '%s'\n",
3783 feed->feed_filename);
3787 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3788 feed->feed_size = lseek(fd, 0, SEEK_END);
3789 /* ensure that we do not wrap before the end of file */
3790 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3791 feed->feed_max_size = feed->feed_size;
3797 /* compute the bandwidth used by each stream */
3798 static void compute_bandwidth(void)
3804 for(stream = first_stream; stream != NULL; stream = stream->next) {
3806 for(i=0;i<stream->nb_streams;i++) {
3807 AVStream *st = stream->streams[i];
3808 switch(st->codec->codec_type) {
3809 case AVMEDIA_TYPE_AUDIO:
3810 case AVMEDIA_TYPE_VIDEO:
3811 bandwidth += st->codec->bit_rate;
3817 stream->bandwidth = (bandwidth + 999) / 1000;
3821 /* add a codec and set the default parameters */
3822 static void add_codec(FFStream *stream, AVCodecContext *av)
3826 /* compute default parameters */
3827 switch(av->codec_type) {
3828 case AVMEDIA_TYPE_AUDIO:
3829 if (av->bit_rate == 0)
3830 av->bit_rate = 64000;
3831 if (av->sample_rate == 0)
3832 av->sample_rate = 22050;
3833 if (av->channels == 0)
3836 case AVMEDIA_TYPE_VIDEO:
3837 if (av->bit_rate == 0)
3838 av->bit_rate = 64000;
3839 if (av->time_base.num == 0){
3840 av->time_base.den = 5;
3841 av->time_base.num = 1;
3843 if (av->width == 0 || av->height == 0) {
3847 /* Bitrate tolerance is less for streaming */
3848 if (av->bit_rate_tolerance == 0)
3849 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3850 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3855 if (av->max_qdiff == 0)
3857 av->qcompress = 0.5;
3860 if (!av->nsse_weight)
3861 av->nsse_weight = 8;
3863 av->frame_skip_cmp = FF_CMP_DCTMAX;
3865 av->me_method = ME_EPZS;
3866 av->rc_buffer_aggressivity = 1.0;
3869 av->rc_eq = "tex^qComp";
3870 if (!av->i_quant_factor)
3871 av->i_quant_factor = -0.8;
3872 if (!av->b_quant_factor)
3873 av->b_quant_factor = 1.25;
3874 if (!av->b_quant_offset)
3875 av->b_quant_offset = 1.25;
3876 if (!av->rc_max_rate)
3877 av->rc_max_rate = av->bit_rate * 2;
3879 if (av->rc_max_rate && !av->rc_buffer_size) {
3880 av->rc_buffer_size = av->rc_max_rate;
3889 st = av_mallocz(sizeof(AVStream));
3892 st->codec = avcodec_alloc_context();
3893 stream->streams[stream->nb_streams++] = st;
3894 memcpy(st->codec, av, sizeof(AVCodecContext));
3897 static enum CodecID opt_audio_codec(const char *arg)
3899 AVCodec *p= avcodec_find_encoder_by_name(arg);
3901 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3902 return CODEC_ID_NONE;
3907 static enum CodecID opt_video_codec(const char *arg)
3909 AVCodec *p= avcodec_find_encoder_by_name(arg);
3911 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3912 return CODEC_ID_NONE;
3917 /* simplistic plugin support */
3920 static void load_module(const char *filename)
3923 void (*init_func)(void);
3924 dll = dlopen(filename, RTLD_NOW);
3926 fprintf(stderr, "Could not load module '%s' - %s\n",
3927 filename, dlerror());
3931 init_func = dlsym(dll, "ffserver_module_init");
3934 "%s: init function 'ffserver_module_init()' not found\n",
3943 static int ffserver_opt_default(const char *opt, const char *arg,
3944 AVCodecContext *avctx, int type)
3947 const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3949 ret = av_set_string3(avctx, opt, arg, 1, NULL);
3953 static int ffserver_opt_preset(const char *arg,
3954 AVCodecContext *avctx, int type,
3955 enum CodecID *audio_id, enum CodecID *video_id)
3958 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3960 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3962 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3963 codec ? codec->name : NULL))) {
3964 fprintf(stderr, "File for preset '%s' not found\n", arg);
3969 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3970 if(line[0] == '#' && !e)
3972 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3974 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3978 if(!strcmp(tmp, "acodec")){
3979 *audio_id = opt_audio_codec(tmp2);
3980 }else if(!strcmp(tmp, "vcodec")){
3981 *video_id = opt_video_codec(tmp2);
3982 }else if(!strcmp(tmp, "scodec")){
3983 /* opt_subtitle_codec(tmp2); */
3984 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3985 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3996 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3997 const char *mime_type)
3999 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4002 AVOutputFormat *stream_fmt;
4003 char stream_format_name[64];
4005 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4006 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4015 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4019 fprintf(stderr, "%s:%d: ", filename, line_num);
4020 vfprintf(stderr, fmt, vl);
4026 static int parse_ffconfig(const char *filename)
4033 int val, errors, line_num;
4034 FFStream **last_stream, *stream, *redirect;
4035 FFStream **last_feed, *feed, *s;
4036 AVCodecContext audio_enc, video_enc;
4037 enum CodecID audio_id, video_id;
4039 f = fopen(filename, "r");
4047 first_stream = NULL;
4048 last_stream = &first_stream;
4050 last_feed = &first_feed;
4054 audio_id = CODEC_ID_NONE;
4055 video_id = CODEC_ID_NONE;
4057 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4059 if (fgets(line, sizeof(line), f) == NULL)
4065 if (*p == '\0' || *p == '#')
4068 get_arg(cmd, sizeof(cmd), &p);
4070 if (!strcasecmp(cmd, "Port")) {
4071 get_arg(arg, sizeof(arg), &p);
4073 if (val < 1 || val > 65536) {
4074 ERROR("Invalid_port: %s\n", arg);
4076 my_http_addr.sin_port = htons(val);
4077 } else if (!strcasecmp(cmd, "BindAddress")) {
4078 get_arg(arg, sizeof(arg), &p);
4079 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4080 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4082 } else if (!strcasecmp(cmd, "NoDaemon")) {
4083 ffserver_daemon = 0;
4084 } else if (!strcasecmp(cmd, "RTSPPort")) {
4085 get_arg(arg, sizeof(arg), &p);
4087 if (val < 1 || val > 65536) {
4088 ERROR("%s:%d: Invalid port: %s\n", arg);
4090 my_rtsp_addr.sin_port = htons(atoi(arg));
4091 } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4092 get_arg(arg, sizeof(arg), &p);
4093 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4094 ERROR("Invalid host/IP address: %s\n", arg);
4096 } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4097 get_arg(arg, sizeof(arg), &p);
4099 if (val < 1 || val > 65536) {
4100 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4102 nb_max_http_connections = val;
4103 } else if (!strcasecmp(cmd, "MaxClients")) {
4104 get_arg(arg, sizeof(arg), &p);
4106 if (val < 1 || val > nb_max_http_connections) {
4107 ERROR("Invalid MaxClients: %s\n", arg);
4109 nb_max_connections = val;
4111 } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4113 get_arg(arg, sizeof(arg), &p);
4115 if (llval < 10 || llval > 10000000) {
4116 ERROR("Invalid MaxBandwidth: %s\n", arg);
4118 max_bandwidth = llval;
4119 } else if (!strcasecmp(cmd, "CustomLog")) {
4120 if (!ffserver_debug)
4121 get_arg(logfilename, sizeof(logfilename), &p);
4122 } else if (!strcasecmp(cmd, "<Feed")) {
4123 /*********************************************/
4124 /* Feed related options */
4126 if (stream || feed) {
4127 ERROR("Already in a tag\n");
4129 feed = av_mallocz(sizeof(FFStream));
4130 get_arg(feed->filename, sizeof(feed->filename), &p);
4131 q = strrchr(feed->filename, '>');
4135 for (s = first_feed; s; s = s->next) {
4136 if (!strcmp(feed->filename, s->filename)) {
4137 ERROR("Feed '%s' already registered\n", s->filename);
4141 feed->fmt = av_guess_format("ffm", NULL, NULL);
4142 /* defaut feed file */
4143 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4144 "/tmp/%s.ffm", feed->filename);
4145 feed->feed_max_size = 5 * 1024 * 1024;
4147 feed->feed = feed; /* self feeding :-) */
4149 /* add in stream list */
4150 *last_stream = feed;
4151 last_stream = &feed->next;
4152 /* add in feed list */
4154 last_feed = &feed->next_feed;
4156 } else if (!strcasecmp(cmd, "Launch")) {
4160 feed->child_argv = av_mallocz(64 * sizeof(char *));
4162 for (i = 0; i < 62; i++) {
4163 get_arg(arg, sizeof(arg), &p);
4167 feed->child_argv[i] = av_strdup(arg);
4170 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4172 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4174 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4175 inet_ntoa(my_http_addr.sin_addr),
4176 ntohs(my_http_addr.sin_port), feed->filename);
4178 } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4180 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4182 } else if (stream) {
4183 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4185 } else if (!strcasecmp(cmd, "File")) {
4187 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4189 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4190 } else if (!strcasecmp(cmd, "Truncate")) {
4192 get_arg(arg, sizeof(arg), &p);
4193 feed->truncate = strtod(arg, NULL);
4195 } else if (!strcasecmp(cmd, "FileMaxSize")) {
4200 get_arg(arg, sizeof(arg), &p);
4202 fsize = strtod(p1, &p1);
4203 switch(toupper(*p1)) {
4208 fsize *= 1024 * 1024;
4211 fsize *= 1024 * 1024 * 1024;
4214 feed->feed_max_size = (int64_t)fsize;
4215 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4216 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4219 } else if (!strcasecmp(cmd, "</Feed>")) {
4221 ERROR("No corresponding <Feed> for </Feed>\n");
4224 } else if (!strcasecmp(cmd, "<Stream")) {
4225 /*********************************************/
4226 /* Stream related options */
4228 if (stream || feed) {
4229 ERROR("Already in a tag\n");
4232 stream = av_mallocz(sizeof(FFStream));
4233 get_arg(stream->filename, sizeof(stream->filename), &p);
4234 q = strrchr(stream->filename, '>');
4238 for (s = first_stream; s; s = s->next) {
4239 if (!strcmp(stream->filename, s->filename)) {
4240 ERROR("Stream '%s' already registered\n", s->filename);
4244 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4245 avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4246 avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4247 audio_id = CODEC_ID_NONE;
4248 video_id = CODEC_ID_NONE;
4250 audio_id = stream->fmt->audio_codec;
4251 video_id = stream->fmt->video_codec;
4254 *last_stream = stream;
4255 last_stream = &stream->next;
4257 } else if (!strcasecmp(cmd, "Feed")) {
4258 get_arg(arg, sizeof(arg), &p);
4263 while (sfeed != NULL) {
4264 if (!strcmp(sfeed->filename, arg))
4266 sfeed = sfeed->next_feed;
4269 ERROR("feed '%s' not defined\n", arg);
4271 stream->feed = sfeed;
4273 } else if (!strcasecmp(cmd, "Format")) {
4274 get_arg(arg, sizeof(arg), &p);
4276 if (!strcmp(arg, "status")) {
4277 stream->stream_type = STREAM_TYPE_STATUS;
4280 stream->stream_type = STREAM_TYPE_LIVE;
4281 /* jpeg cannot be used here, so use single frame jpeg */
4282 if (!strcmp(arg, "jpeg"))
4283 strcpy(arg, "mjpeg");
4284 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4286 ERROR("Unknown Format: %s\n", arg);
4290 audio_id = stream->fmt->audio_codec;
4291 video_id = stream->fmt->video_codec;
4294 } else if (!strcasecmp(cmd, "InputFormat")) {
4295 get_arg(arg, sizeof(arg), &p);
4297 stream->ifmt = av_find_input_format(arg);
4298 if (!stream->ifmt) {
4299 ERROR("Unknown input format: %s\n", arg);
4302 } else if (!strcasecmp(cmd, "FaviconURL")) {
4303 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4304 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4306 ERROR("FaviconURL only permitted for status streams\n");
4308 } else if (!strcasecmp(cmd, "Author")) {
4310 get_arg(stream->author, sizeof(stream->author), &p);
4311 } else if (!strcasecmp(cmd, "Comment")) {
4313 get_arg(stream->comment, sizeof(stream->comment), &p);
4314 } else if (!strcasecmp(cmd, "Copyright")) {
4316 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4317 } else if (!strcasecmp(cmd, "Title")) {
4319 get_arg(stream->title, sizeof(stream->title), &p);
4320 } else if (!strcasecmp(cmd, "Preroll")) {
4321 get_arg(arg, sizeof(arg), &p);
4323 stream->prebuffer = atof(arg) * 1000;
4324 } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4326 stream->send_on_key = 1;
4327 } else if (!strcasecmp(cmd, "AudioCodec")) {
4328 get_arg(arg, sizeof(arg), &p);
4329 audio_id = opt_audio_codec(arg);
4330 if (audio_id == CODEC_ID_NONE) {
4331 ERROR("Unknown AudioCodec: %s\n", arg);
4333 } else if (!strcasecmp(cmd, "VideoCodec")) {
4334 get_arg(arg, sizeof(arg), &p);
4335 video_id = opt_video_codec(arg);
4336 if (video_id == CODEC_ID_NONE) {
4337 ERROR("Unknown VideoCodec: %s\n", arg);
4339 } else if (!strcasecmp(cmd, "MaxTime")) {
4340 get_arg(arg, sizeof(arg), &p);
4342 stream->max_time = atof(arg) * 1000;
4343 } else if (!strcasecmp(cmd, "AudioBitRate")) {
4344 get_arg(arg, sizeof(arg), &p);
4346 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4347 } else if (!strcasecmp(cmd, "AudioChannels")) {
4348 get_arg(arg, sizeof(arg), &p);
4350 audio_enc.channels = atoi(arg);
4351 } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4352 get_arg(arg, sizeof(arg), &p);
4354 audio_enc.sample_rate = atoi(arg);
4355 } else if (!strcasecmp(cmd, "AudioQuality")) {
4356 get_arg(arg, sizeof(arg), &p);
4358 // audio_enc.quality = atof(arg) * 1000;
4360 } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4362 int minrate, maxrate;
4364 get_arg(arg, sizeof(arg), &p);
4366 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4367 video_enc.rc_min_rate = minrate * 1000;
4368 video_enc.rc_max_rate = maxrate * 1000;
4370 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4373 } else if (!strcasecmp(cmd, "Debug")) {
4375 get_arg(arg, sizeof(arg), &p);
4376 video_enc.debug = strtol(arg,0,0);
4378 } else if (!strcasecmp(cmd, "Strict")) {
4380 get_arg(arg, sizeof(arg), &p);
4381 video_enc.strict_std_compliance = atoi(arg);
4383 } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4385 get_arg(arg, sizeof(arg), &p);
4386 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4388 } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4390 get_arg(arg, sizeof(arg), &p);
4391 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4393 } else if (!strcasecmp(cmd, "VideoBitRate")) {
4394 get_arg(arg, sizeof(arg), &p);
4396 video_enc.bit_rate = atoi(arg) * 1000;
4398 } else if (!strcasecmp(cmd, "VideoSize")) {
4399 get_arg(arg, sizeof(arg), &p);
4401 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4402 if ((video_enc.width % 16) != 0 ||
4403 (video_enc.height % 16) != 0) {
4404 ERROR("Image size must be a multiple of 16\n");
4407 } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4408 get_arg(arg, sizeof(arg), &p);
4410 AVRational frame_rate;
4411 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4412 ERROR("Incorrect frame rate: %s\n", arg);
4414 video_enc.time_base.num = frame_rate.den;
4415 video_enc.time_base.den = frame_rate.num;
4418 } else if (!strcasecmp(cmd, "VideoGopSize")) {
4419 get_arg(arg, sizeof(arg), &p);
4421 video_enc.gop_size = atoi(arg);
4422 } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4424 video_enc.gop_size = 1;
4425 } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4427 video_enc.mb_decision = FF_MB_DECISION_BITS;
4428 } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4430 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4431 video_enc.flags |= CODEC_FLAG_4MV;
4433 } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4434 !strcasecmp(cmd, "AVOptionAudio")) {
4436 AVCodecContext *avctx;
4438 get_arg(arg, sizeof(arg), &p);
4439 get_arg(arg2, sizeof(arg2), &p);
4440 if (!strcasecmp(cmd, "AVOptionVideo")) {
4442 type = AV_OPT_FLAG_VIDEO_PARAM;
4445 type = AV_OPT_FLAG_AUDIO_PARAM;
4447 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4448 ERROR("AVOption error: %s %s\n", arg, arg2);
4450 } else if (!strcasecmp(cmd, "AVPresetVideo") ||
4451 !strcasecmp(cmd, "AVPresetAudio")) {
4452 AVCodecContext *avctx;
4454 get_arg(arg, sizeof(arg), &p);
4455 if (!strcasecmp(cmd, "AVPresetVideo")) {
4457 video_enc.codec_id = video_id;
4458 type = AV_OPT_FLAG_VIDEO_PARAM;
4461 audio_enc.codec_id = audio_id;
4462 type = AV_OPT_FLAG_AUDIO_PARAM;
4464 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4465 ERROR("AVPreset error: %s\n", arg);
4467 } else if (!strcasecmp(cmd, "VideoTag")) {
4468 get_arg(arg, sizeof(arg), &p);
4469 if ((strlen(arg) == 4) && stream)
4470 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4471 } else if (!strcasecmp(cmd, "BitExact")) {
4473 video_enc.flags |= CODEC_FLAG_BITEXACT;
4474 } else if (!strcasecmp(cmd, "DctFastint")) {
4476 video_enc.dct_algo = FF_DCT_FASTINT;
4477 } else if (!strcasecmp(cmd, "IdctSimple")) {
4479 video_enc.idct_algo = FF_IDCT_SIMPLE;
4480 } else if (!strcasecmp(cmd, "Qscale")) {
4481 get_arg(arg, sizeof(arg), &p);
4483 video_enc.flags |= CODEC_FLAG_QSCALE;
4484 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4486 } else if (!strcasecmp(cmd, "VideoQDiff")) {
4487 get_arg(arg, sizeof(arg), &p);
4489 video_enc.max_qdiff = atoi(arg);
4490 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4491 ERROR("VideoQDiff out of range\n");
4494 } else if (!strcasecmp(cmd, "VideoQMax")) {
4495 get_arg(arg, sizeof(arg), &p);
4497 video_enc.qmax = atoi(arg);
4498 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4499 ERROR("VideoQMax out of range\n");
4502 } else if (!strcasecmp(cmd, "VideoQMin")) {
4503 get_arg(arg, sizeof(arg), &p);
4505 video_enc.qmin = atoi(arg);
4506 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4507 ERROR("VideoQMin out of range\n");
4510 } else if (!strcasecmp(cmd, "LumaElim")) {
4511 get_arg(arg, sizeof(arg), &p);
4513 video_enc.luma_elim_threshold = atoi(arg);
4514 } else if (!strcasecmp(cmd, "ChromaElim")) {
4515 get_arg(arg, sizeof(arg), &p);
4517 video_enc.chroma_elim_threshold = atoi(arg);
4518 } else if (!strcasecmp(cmd, "LumiMask")) {
4519 get_arg(arg, sizeof(arg), &p);
4521 video_enc.lumi_masking = atof(arg);
4522 } else if (!strcasecmp(cmd, "DarkMask")) {
4523 get_arg(arg, sizeof(arg), &p);
4525 video_enc.dark_masking = atof(arg);
4526 } else if (!strcasecmp(cmd, "NoVideo")) {
4527 video_id = CODEC_ID_NONE;
4528 } else if (!strcasecmp(cmd, "NoAudio")) {
4529 audio_id = CODEC_ID_NONE;
4530 } else if (!strcasecmp(cmd, "ACL")) {
4531 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4532 } else if (!strcasecmp(cmd, "DynamicACL")) {
4534 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4536 } else if (!strcasecmp(cmd, "RTSPOption")) {
4537 get_arg(arg, sizeof(arg), &p);
4539 av_freep(&stream->rtsp_option);
4540 stream->rtsp_option = av_strdup(arg);
4542 } else if (!strcasecmp(cmd, "MulticastAddress")) {
4543 get_arg(arg, sizeof(arg), &p);
4545 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4546 ERROR("Invalid host/IP address: %s\n", arg);
4548 stream->is_multicast = 1;
4549 stream->loop = 1; /* default is looping */
4551 } else if (!strcasecmp(cmd, "MulticastPort")) {
4552 get_arg(arg, sizeof(arg), &p);
4554 stream->multicast_port = atoi(arg);
4555 } else if (!strcasecmp(cmd, "MulticastTTL")) {
4556 get_arg(arg, sizeof(arg), &p);
4558 stream->multicast_ttl = atoi(arg);
4559 } else if (!strcasecmp(cmd, "NoLoop")) {
4562 } else if (!strcasecmp(cmd, "</Stream>")) {
4564 ERROR("No corresponding <Stream> for </Stream>\n");
4566 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4567 if (audio_id != CODEC_ID_NONE) {
4568 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4569 audio_enc.codec_id = audio_id;
4570 add_codec(stream, &audio_enc);
4572 if (video_id != CODEC_ID_NONE) {
4573 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4574 video_enc.codec_id = video_id;
4575 add_codec(stream, &video_enc);
4580 } else if (!strcasecmp(cmd, "<Redirect")) {
4581 /*********************************************/
4583 if (stream || feed || redirect) {
4584 ERROR("Already in a tag\n");
4586 redirect = av_mallocz(sizeof(FFStream));
4587 *last_stream = redirect;
4588 last_stream = &redirect->next;
4590 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4591 q = strrchr(redirect->filename, '>');
4594 redirect->stream_type = STREAM_TYPE_REDIRECT;
4596 } else if (!strcasecmp(cmd, "URL")) {
4598 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4599 } else if (!strcasecmp(cmd, "</Redirect>")) {
4601 ERROR("No corresponding <Redirect> for </Redirect>\n");
4603 if (!redirect->feed_filename[0]) {
4604 ERROR("No URL found for <Redirect>\n");
4608 } else if (!strcasecmp(cmd, "LoadModule")) {
4609 get_arg(arg, sizeof(arg), &p);
4613 ERROR("Module support not compiled into this version: '%s'\n", arg);
4616 ERROR("Incorrect keyword: '%s'\n", cmd);
4628 static void handle_child_exit(int sig)
4633 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4636 for (feed = first_feed; feed; feed = feed->next) {
4637 if (feed->pid == pid) {
4638 int uptime = time(0) - feed->pid_start;
4641 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4644 /* Turn off any more restarts */
4645 feed->child_argv = 0;
4650 need_to_start_children = 1;
4653 static void opt_debug(void)
4656 ffserver_daemon = 0;
4657 logfilename[0] = '-';
4660 static void show_help(void)
4662 printf("usage: ffserver [options]\n"
4663 "Hyper fast multi format Audio/Video streaming server\n");
4665 show_help_options(options, "Main options:\n", 0, 0);
4668 static const OptionDef options[] = {
4669 #include "cmdutils_common_opts.h"
4670 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4671 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4672 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4676 int main(int argc, char **argv)
4678 struct sigaction sigact;
4684 my_program_name = argv[0];
4685 my_program_dir = getcwd(0, 0);
4686 ffserver_daemon = 1;
4688 parse_options(argc, argv, options, NULL);
4690 unsetenv("http_proxy"); /* Kill the http_proxy */
4692 av_lfg_init(&random_state, av_get_random_seed());
4694 memset(&sigact, 0, sizeof(sigact));
4695 sigact.sa_handler = handle_child_exit;
4696 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4697 sigaction(SIGCHLD, &sigact, 0);
4699 if (parse_ffconfig(config_filename) < 0) {
4700 fprintf(stderr, "Incorrect config file - exiting.\n");
4704 /* open log file if needed */
4705 if (logfilename[0] != '\0') {
4706 if (!strcmp(logfilename, "-"))
4709 logfile = fopen(logfilename, "a");
4710 av_log_set_callback(http_av_log);
4713 build_file_streams();
4715 build_feed_streams();
4717 compute_bandwidth();
4719 /* put the process in background and detach it from its TTY */
4720 if (ffserver_daemon) {
4727 } else if (pid > 0) {
4734 open("/dev/null", O_RDWR);
4735 if (strcmp(logfilename, "-") != 0) {
4745 signal(SIGPIPE, SIG_IGN);
4747 if (ffserver_daemon)
4750 if (http_server() < 0) {
4751 http_log("Could not start server\n");