2 * Multiple format streaming server
3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
5 * This file is part of Libav.
7 * Libav 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 * Libav 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 Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #define _XOPEN_SOURCE 600
26 #define closesocket close
31 #include "libavformat/avformat.h"
32 #include "libavformat/ffm.h"
33 #include "libavformat/network.h"
34 #include "libavformat/os_support.h"
35 #include "libavformat/rtpdec.h"
36 #include "libavformat/rtsp.h"
37 // XXX for ffio_open_dyn_packet_buffer, to be removed
38 #include "libavformat/avio_internal.h"
39 #include "libavutil/avstring.h"
40 #include "libavutil/lfg.h"
41 #include "libavutil/random_seed.h"
42 #include "libavutil/parseutils.h"
43 #include "libavcodec/opt.h"
47 #include <sys/ioctl.h>
62 const char program_name[] = "FFserver";
63 const int program_birth_year = 2000;
65 static const OptionDef options[];
68 HTTPSTATE_WAIT_REQUEST,
69 HTTPSTATE_SEND_HEADER,
70 HTTPSTATE_SEND_DATA_HEADER,
71 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
72 HTTPSTATE_SEND_DATA_TRAILER,
73 HTTPSTATE_RECEIVE_DATA,
74 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
77 RTSPSTATE_WAIT_REQUEST,
79 RTSPSTATE_SEND_PACKET,
82 static const char *http_state[] = {
98 #if !FF_API_MAX_STREAMS
99 #define MAX_STREAMS 20
102 #define IOBUFFER_INIT_SIZE 8192
104 /* timeouts are in ms */
105 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
106 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
108 #define SYNC_TIMEOUT (10 * 1000)
110 typedef struct RTSPActionServerSetup {
112 char transport_option[512];
113 } RTSPActionServerSetup;
116 int64_t count1, count2;
117 int64_t time1, time2;
120 /* context associated with one connection */
121 typedef struct HTTPContext {
122 enum HTTPState state;
123 int fd; /* socket file descriptor */
124 struct sockaddr_in from_addr; /* origin */
125 struct pollfd *poll_entry; /* used when polling */
127 uint8_t *buffer_ptr, *buffer_end;
130 int chunked_encoding;
131 int chunk_size; /* 0 if it needs to be read */
132 struct HTTPContext *next;
133 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
137 /* input format handling */
138 AVFormatContext *fmt_in;
139 int64_t start_time; /* In milliseconds - this wraps fairly often */
140 int64_t first_pts; /* initial pts value */
141 int64_t cur_pts; /* current pts value from the stream in us */
142 int64_t cur_frame_duration; /* duration of the current frame in us */
143 int cur_frame_bytes; /* output frame size, needed to compute
144 the time at which we send each
146 int pts_stream_index; /* stream we choose as clock reference */
147 int64_t cur_clock; /* current clock reference value in us */
148 /* output format handling */
149 struct FFStream *stream;
150 /* -1 is invalid stream */
151 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
152 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
154 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
155 int last_packet_sent; /* true if last data packet was sent */
157 DataRateData datarate;
164 int is_packetized; /* if true, the stream is packetized */
165 int packet_stream_index; /* current stream for output in state machine */
167 /* RTSP state specific */
168 uint8_t *pb_buffer; /* XXX: use that in all the code */
170 int seq; /* RTSP sequence number */
172 /* RTP state specific */
173 enum RTSPLowerTransport rtp_protocol;
174 char session_id[32]; /* session id */
175 AVFormatContext *rtp_ctx[MAX_STREAMS];
177 /* RTP/UDP specific */
178 URLContext *rtp_handles[MAX_STREAMS];
180 /* RTP/TCP specific */
181 struct HTTPContext *rtsp_c;
182 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
185 /* each generated stream is described here */
189 STREAM_TYPE_REDIRECT,
192 enum IPAddressAction {
197 typedef struct IPAddressACL {
198 struct IPAddressACL *next;
199 enum IPAddressAction action;
200 /* These are in host order */
201 struct in_addr first;
205 /* description of each stream of the ffserver.conf file */
206 typedef struct FFStream {
207 enum StreamType stream_type;
208 char filename[1024]; /* stream filename */
209 struct FFStream *feed; /* feed we are using (can be null if
211 AVFormatParameters *ap_in; /* input parameters */
212 AVInputFormat *ifmt; /* if non NULL, force input format */
215 char dynamic_acl[1024];
217 int prebuffer; /* Number of millseconds early to start */
218 int64_t max_time; /* Number of milliseconds to run */
220 AVStream *streams[MAX_STREAMS];
221 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
222 char feed_filename[1024]; /* file name of the feed storage, or
223 input file name for a stream */
228 pid_t pid; /* Of ffmpeg process */
229 time_t pid_start; /* Of ffmpeg process */
231 struct FFStream *next;
232 unsigned bandwidth; /* bandwidth, in kbits/s */
235 /* multicast specific */
237 struct in_addr multicast_ip;
238 int multicast_port; /* first port used for multicast */
240 int loop; /* if true, send the stream in loops (only meaningful if file) */
243 int feed_opened; /* true if someone is writing to the feed */
244 int is_feed; /* true if it is a feed */
245 int readonly; /* True if writing is prohibited to the file */
246 int truncate; /* True if feeder connection truncate the feed file */
248 int64_t bytes_served;
249 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
250 int64_t feed_write_index; /* current write position in feed (it wraps around) */
251 int64_t feed_size; /* current size of feed */
252 struct FFStream *next_feed;
255 typedef struct FeedData {
256 long long data_count;
257 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
260 static struct sockaddr_in my_http_addr;
261 static struct sockaddr_in my_rtsp_addr;
263 static char logfilename[1024];
264 static HTTPContext *first_http_ctx;
265 static FFStream *first_feed; /* contains only feeds */
266 static FFStream *first_stream; /* contains all streams, including feeds */
268 static void new_connection(int server_fd, int is_rtsp);
269 static void close_connection(HTTPContext *c);
272 static int handle_connection(HTTPContext *c);
273 static int http_parse_request(HTTPContext *c);
274 static int http_send_data(HTTPContext *c);
275 static void compute_status(HTTPContext *c);
276 static int open_input_stream(HTTPContext *c, const char *info);
277 static int http_start_receive_data(HTTPContext *c);
278 static int http_receive_data(HTTPContext *c);
281 static int rtsp_parse_request(HTTPContext *c);
282 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
283 static void rtsp_cmd_options(HTTPContext *c, const char *url);
284 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
285 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
286 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
287 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
290 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
291 struct in_addr my_ip);
294 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
295 FFStream *stream, const char *session_id,
296 enum RTSPLowerTransport rtp_protocol);
297 static int rtp_new_av_stream(HTTPContext *c,
298 int stream_index, struct sockaddr_in *dest_addr,
299 HTTPContext *rtsp_c);
301 static const char *my_program_name;
302 static const char *my_program_dir;
304 static const char *config_filename = "/etc/ffserver.conf";
306 static int ffserver_debug;
307 static int ffserver_daemon;
308 static int no_launch;
309 static int need_to_start_children;
311 /* maximum number of simultaneous HTTP connections */
312 static unsigned int nb_max_http_connections = 2000;
313 static unsigned int nb_max_connections = 5;
314 static unsigned int nb_connections;
316 static uint64_t max_bandwidth = 1000;
317 static uint64_t current_bandwidth;
319 static int64_t cur_time; // Making this global saves on passing it around everywhere
321 static AVLFG random_state;
323 static FILE *logfile = NULL;
325 /* FIXME: make ffserver work with IPv6 */
326 /* resolve host with also IP address parsing */
327 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
330 if (!ff_inet_aton(hostname, sin_addr)) {
332 struct addrinfo *ai, *cur;
333 struct addrinfo hints;
334 memset(&hints, 0, sizeof(hints));
335 hints.ai_family = AF_INET;
336 if (getaddrinfo(hostname, NULL, &hints, &ai))
338 /* getaddrinfo returns a linked list of addrinfo structs.
339 * Even if we set ai_family = AF_INET above, make sure
340 * that the returned one actually is of the correct type. */
341 for (cur = ai; cur; cur = cur->ai_next) {
342 if (cur->ai_family == AF_INET) {
343 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
352 hp = gethostbyname(hostname);
355 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
361 static char *ctime1(char *buf2)
369 p = buf2 + strlen(p) - 1;
375 static void http_vlog(const char *fmt, va_list vargs)
377 static int print_prefix = 1;
382 fprintf(logfile, "%s ", buf);
384 print_prefix = strstr(fmt, "\n") != NULL;
385 vfprintf(logfile, fmt, vargs);
391 __attribute__ ((format (printf, 1, 2)))
393 static void http_log(const char *fmt, ...)
396 va_start(vargs, fmt);
397 http_vlog(fmt, vargs);
401 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
403 static int print_prefix = 1;
404 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
405 if (level > av_log_get_level())
407 if (print_prefix && avc)
408 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
409 print_prefix = strstr(fmt, "\n") != NULL;
410 http_vlog(fmt, vargs);
413 static void log_connection(HTTPContext *c)
418 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
419 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
420 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
423 static void update_datarate(DataRateData *drd, int64_t count)
425 if (!drd->time1 && !drd->count1) {
426 drd->time1 = drd->time2 = cur_time;
427 drd->count1 = drd->count2 = count;
428 } else if (cur_time - drd->time2 > 5000) {
429 drd->time1 = drd->time2;
430 drd->count1 = drd->count2;
431 drd->time2 = cur_time;
436 /* In bytes per second */
437 static int compute_datarate(DataRateData *drd, int64_t count)
439 if (cur_time == drd->time1)
442 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
446 static void start_children(FFStream *feed)
451 for (; feed; feed = feed->next) {
452 if (feed->child_argv && !feed->pid) {
453 feed->pid_start = time(0);
458 http_log("Unable to create children\n");
467 av_strlcpy(pathname, my_program_name, sizeof(pathname));
469 slash = strrchr(pathname, '/');
474 strcpy(slash, "ffmpeg");
476 http_log("Launch commandline: ");
477 http_log("%s ", pathname);
478 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
479 http_log("%s ", feed->child_argv[i]);
482 for (i = 3; i < 256; i++)
485 if (!ffserver_debug) {
486 i = open("/dev/null", O_RDWR);
495 /* This is needed to make relative pathnames work */
496 chdir(my_program_dir);
498 signal(SIGPIPE, SIG_DFL);
500 execvp(pathname, feed->child_argv);
508 /* open a listening socket */
509 static int socket_open_listen(struct sockaddr_in *my_addr)
513 server_fd = socket(AF_INET,SOCK_STREAM,0);
520 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
522 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
524 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
526 closesocket(server_fd);
530 if (listen (server_fd, 5) < 0) {
532 closesocket(server_fd);
535 ff_socket_nonblock(server_fd, 1);
540 /* start all multicast streams */
541 static void start_multicast(void)
546 struct sockaddr_in dest_addr;
547 int default_port, stream_index;
550 for(stream = first_stream; stream != NULL; stream = stream->next) {
551 if (stream->is_multicast) {
552 /* open the RTP connection */
553 snprintf(session_id, sizeof(session_id), "%08x%08x",
554 av_lfg_get(&random_state), av_lfg_get(&random_state));
556 /* choose a port if none given */
557 if (stream->multicast_port == 0) {
558 stream->multicast_port = default_port;
562 dest_addr.sin_family = AF_INET;
563 dest_addr.sin_addr = stream->multicast_ip;
564 dest_addr.sin_port = htons(stream->multicast_port);
566 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
567 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
571 if (open_input_stream(rtp_c, "") < 0) {
572 http_log("Could not open input stream for stream '%s'\n",
577 /* open each RTP stream */
578 for(stream_index = 0; stream_index < stream->nb_streams;
580 dest_addr.sin_port = htons(stream->multicast_port +
582 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
583 http_log("Could not open output stream '%s/streamid=%d'\n",
584 stream->filename, stream_index);
589 /* change state to send data */
590 rtp_c->state = HTTPSTATE_SEND_DATA;
595 /* main loop of the http server */
596 static int http_server(void)
598 int server_fd = 0, rtsp_server_fd = 0;
599 int ret, delay, delay1;
600 struct pollfd *poll_table, *poll_entry;
601 HTTPContext *c, *c_next;
603 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
604 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
608 if (my_http_addr.sin_port) {
609 server_fd = socket_open_listen(&my_http_addr);
614 if (my_rtsp_addr.sin_port) {
615 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
616 if (rtsp_server_fd < 0)
620 if (!rtsp_server_fd && !server_fd) {
621 http_log("HTTP and RTSP disabled.\n");
625 http_log("FFserver started.\n");
627 start_children(first_feed);
632 poll_entry = poll_table;
634 poll_entry->fd = server_fd;
635 poll_entry->events = POLLIN;
638 if (rtsp_server_fd) {
639 poll_entry->fd = rtsp_server_fd;
640 poll_entry->events = POLLIN;
644 /* wait for events on each HTTP handle */
651 case HTTPSTATE_SEND_HEADER:
652 case RTSPSTATE_SEND_REPLY:
653 case RTSPSTATE_SEND_PACKET:
654 c->poll_entry = poll_entry;
656 poll_entry->events = POLLOUT;
659 case HTTPSTATE_SEND_DATA_HEADER:
660 case HTTPSTATE_SEND_DATA:
661 case HTTPSTATE_SEND_DATA_TRAILER:
662 if (!c->is_packetized) {
663 /* for TCP, we output as much as we can (may need to put a limit) */
664 c->poll_entry = poll_entry;
666 poll_entry->events = POLLOUT;
669 /* when ffserver is doing the timing, we work by
670 looking at which packet need to be sent every
672 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
677 case HTTPSTATE_WAIT_REQUEST:
678 case HTTPSTATE_RECEIVE_DATA:
679 case HTTPSTATE_WAIT_FEED:
680 case RTSPSTATE_WAIT_REQUEST:
681 /* need to catch errors */
682 c->poll_entry = poll_entry;
684 poll_entry->events = POLLIN;/* Maybe this will work */
688 c->poll_entry = NULL;
694 /* wait for an event on one connection. We poll at least every
695 second to handle timeouts */
697 ret = poll(poll_table, poll_entry - poll_table, delay);
698 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
699 ff_neterrno() != AVERROR(EINTR))
703 cur_time = av_gettime() / 1000;
705 if (need_to_start_children) {
706 need_to_start_children = 0;
707 start_children(first_feed);
710 /* now handle the events */
711 for(c = first_http_ctx; c != NULL; c = c_next) {
713 if (handle_connection(c) < 0) {
714 /* close and free the connection */
720 poll_entry = poll_table;
722 /* new HTTP connection request ? */
723 if (poll_entry->revents & POLLIN)
724 new_connection(server_fd, 0);
727 if (rtsp_server_fd) {
728 /* new RTSP connection request ? */
729 if (poll_entry->revents & POLLIN)
730 new_connection(rtsp_server_fd, 1);
735 /* start waiting for a new HTTP/RTSP request */
736 static void start_wait_request(HTTPContext *c, int is_rtsp)
738 c->buffer_ptr = c->buffer;
739 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
742 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
743 c->state = RTSPSTATE_WAIT_REQUEST;
745 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
746 c->state = HTTPSTATE_WAIT_REQUEST;
750 static void http_send_too_busy_reply(int fd)
753 int len = snprintf(buffer, sizeof(buffer),
754 "HTTP/1.0 503 Server too busy\r\n"
755 "Content-type: text/html\r\n"
757 "<html><head><title>Too busy</title></head><body>\r\n"
758 "<p>The server is too busy to serve your request at this time.</p>\r\n"
759 "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
760 "</body></html>\r\n",
761 nb_connections, nb_max_connections);
762 send(fd, buffer, len, 0);
766 static void new_connection(int server_fd, int is_rtsp)
768 struct sockaddr_in from_addr;
770 HTTPContext *c = NULL;
772 len = sizeof(from_addr);
773 fd = accept(server_fd, (struct sockaddr *)&from_addr,
776 http_log("error during accept %s\n", strerror(errno));
779 ff_socket_nonblock(fd, 1);
781 if (nb_connections >= nb_max_connections) {
782 http_send_too_busy_reply(fd);
786 /* add a new connection */
787 c = av_mallocz(sizeof(HTTPContext));
792 c->poll_entry = NULL;
793 c->from_addr = from_addr;
794 c->buffer_size = IOBUFFER_INIT_SIZE;
795 c->buffer = av_malloc(c->buffer_size);
799 c->next = first_http_ctx;
803 start_wait_request(c, is_rtsp);
815 static void close_connection(HTTPContext *c)
817 HTTPContext **cp, *c1;
819 AVFormatContext *ctx;
823 /* remove connection from list */
824 cp = &first_http_ctx;
825 while ((*cp) != NULL) {
833 /* remove references, if any (XXX: do it faster) */
834 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
839 /* remove connection associated resources */
843 /* close each frame parser */
844 for(i=0;i<c->fmt_in->nb_streams;i++) {
845 st = c->fmt_in->streams[i];
846 if (st->codec->codec)
847 avcodec_close(st->codec);
849 av_close_input_file(c->fmt_in);
852 /* free RTP output streams if any */
855 nb_streams = c->stream->nb_streams;
857 for(i=0;i<nb_streams;i++) {
860 av_write_trailer(ctx);
861 av_metadata_free(&ctx->metadata);
862 av_free(ctx->streams[0]);
865 h = c->rtp_handles[i];
872 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
875 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
876 av_write_trailer(ctx);
877 av_freep(&c->pb_buffer);
878 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
883 for(i=0; i<ctx->nb_streams; i++)
884 av_free(ctx->streams[i]);
886 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
887 current_bandwidth -= c->stream->bandwidth;
889 /* signal that there is no feed if we are the feeder socket */
890 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
891 c->stream->feed_opened = 0;
895 av_freep(&c->pb_buffer);
896 av_freep(&c->packet_buffer);
902 static int handle_connection(HTTPContext *c)
907 case HTTPSTATE_WAIT_REQUEST:
908 case RTSPSTATE_WAIT_REQUEST:
910 if ((c->timeout - cur_time) < 0)
912 if (c->poll_entry->revents & (POLLERR | POLLHUP))
915 /* no need to read if no events */
916 if (!(c->poll_entry->revents & POLLIN))
920 len = recv(c->fd, c->buffer_ptr, 1, 0);
922 if (ff_neterrno() != AVERROR(EAGAIN) &&
923 ff_neterrno() != AVERROR(EINTR))
925 } else if (len == 0) {
928 /* search for end of request. */
930 c->buffer_ptr += len;
932 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
933 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
934 /* request found : parse it and reply */
935 if (c->state == HTTPSTATE_WAIT_REQUEST) {
936 ret = http_parse_request(c);
938 ret = rtsp_parse_request(c);
942 } else if (ptr >= c->buffer_end) {
943 /* request too long: cannot do anything */
945 } else goto read_loop;
949 case HTTPSTATE_SEND_HEADER:
950 if (c->poll_entry->revents & (POLLERR | POLLHUP))
953 /* no need to write if no events */
954 if (!(c->poll_entry->revents & POLLOUT))
956 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
958 if (ff_neterrno() != AVERROR(EAGAIN) &&
959 ff_neterrno() != AVERROR(EINTR)) {
960 /* error : close connection */
961 av_freep(&c->pb_buffer);
965 c->buffer_ptr += len;
967 c->stream->bytes_served += len;
968 c->data_count += len;
969 if (c->buffer_ptr >= c->buffer_end) {
970 av_freep(&c->pb_buffer);
974 /* all the buffer was sent : synchronize to the incoming stream */
975 c->state = HTTPSTATE_SEND_DATA_HEADER;
976 c->buffer_ptr = c->buffer_end = c->buffer;
981 case HTTPSTATE_SEND_DATA:
982 case HTTPSTATE_SEND_DATA_HEADER:
983 case HTTPSTATE_SEND_DATA_TRAILER:
984 /* for packetized output, we consider we can always write (the
985 input streams sets the speed). It may be better to verify
986 that we do not rely too much on the kernel queues */
987 if (!c->is_packetized) {
988 if (c->poll_entry->revents & (POLLERR | POLLHUP))
991 /* no need to read if no events */
992 if (!(c->poll_entry->revents & POLLOUT))
995 if (http_send_data(c) < 0)
997 /* close connection if trailer sent */
998 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1001 case HTTPSTATE_RECEIVE_DATA:
1002 /* no need to read if no events */
1003 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1005 if (!(c->poll_entry->revents & POLLIN))
1007 if (http_receive_data(c) < 0)
1010 case HTTPSTATE_WAIT_FEED:
1011 /* no need to read if no events */
1012 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1015 /* nothing to do, we'll be waken up by incoming feed packets */
1018 case RTSPSTATE_SEND_REPLY:
1019 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1020 av_freep(&c->pb_buffer);
1023 /* no need to write if no events */
1024 if (!(c->poll_entry->revents & POLLOUT))
1026 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1028 if (ff_neterrno() != AVERROR(EAGAIN) &&
1029 ff_neterrno() != AVERROR(EINTR)) {
1030 /* error : close connection */
1031 av_freep(&c->pb_buffer);
1035 c->buffer_ptr += len;
1036 c->data_count += len;
1037 if (c->buffer_ptr >= c->buffer_end) {
1038 /* all the buffer was sent : wait for a new request */
1039 av_freep(&c->pb_buffer);
1040 start_wait_request(c, 1);
1044 case RTSPSTATE_SEND_PACKET:
1045 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1046 av_freep(&c->packet_buffer);
1049 /* no need to write if no events */
1050 if (!(c->poll_entry->revents & POLLOUT))
1052 len = send(c->fd, c->packet_buffer_ptr,
1053 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1055 if (ff_neterrno() != AVERROR(EAGAIN) &&
1056 ff_neterrno() != AVERROR(EINTR)) {
1057 /* error : close connection */
1058 av_freep(&c->packet_buffer);
1062 c->packet_buffer_ptr += len;
1063 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1064 /* all the buffer was sent : wait for a new request */
1065 av_freep(&c->packet_buffer);
1066 c->state = RTSPSTATE_WAIT_REQUEST;
1070 case HTTPSTATE_READY:
1079 static int extract_rates(char *rates, int ratelen, const char *request)
1083 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1084 if (strncasecmp(p, "Pragma:", 7) == 0) {
1085 const char *q = p + 7;
1087 while (*q && *q != '\n' && isspace(*q))
1090 if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1096 memset(rates, 0xff, ratelen);
1099 while (*q && *q != '\n' && *q != ':')
1102 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1106 if (stream_no < ratelen && stream_no >= 0)
1107 rates[stream_no] = rate_no;
1109 while (*q && *q != '\n' && !isspace(*q))
1116 p = strchr(p, '\n');
1126 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1129 int best_bitrate = 100000000;
1132 for (i = 0; i < feed->nb_streams; i++) {
1133 AVCodecContext *feed_codec = feed->streams[i]->codec;
1135 if (feed_codec->codec_id != codec->codec_id ||
1136 feed_codec->sample_rate != codec->sample_rate ||
1137 feed_codec->width != codec->width ||
1138 feed_codec->height != codec->height)
1141 /* Potential stream */
1143 /* We want the fastest stream less than bit_rate, or the slowest
1144 * faster than bit_rate
1147 if (feed_codec->bit_rate <= bit_rate) {
1148 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1149 best_bitrate = feed_codec->bit_rate;
1153 if (feed_codec->bit_rate < best_bitrate) {
1154 best_bitrate = feed_codec->bit_rate;
1163 static int modify_current_stream(HTTPContext *c, char *rates)
1166 FFStream *req = c->stream;
1167 int action_required = 0;
1169 /* Not much we can do for a feed */
1173 for (i = 0; i < req->nb_streams; i++) {
1174 AVCodecContext *codec = req->streams[i]->codec;
1178 c->switch_feed_streams[i] = req->feed_streams[i];
1181 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1184 /* Wants off or slow */
1185 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1187 /* This doesn't work well when it turns off the only stream! */
1188 c->switch_feed_streams[i] = -2;
1189 c->feed_streams[i] = -2;
1194 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1195 action_required = 1;
1198 return action_required;
1201 /* XXX: factorize in utils.c ? */
1202 /* XXX: take care with different space meaning */
1203 static void skip_spaces(const char **pp)
1207 while (*p == ' ' || *p == '\t')
1212 static void get_word(char *buf, int buf_size, const char **pp)
1220 while (!isspace(*p) && *p != '\0') {
1221 if ((q - buf) < buf_size - 1)
1230 static void get_arg(char *buf, int buf_size, const char **pp)
1237 while (isspace(*p)) p++;
1240 if (*p == '\"' || *p == '\'')
1252 if ((q - buf) < buf_size - 1)
1257 if (quote && *p == quote)
1262 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1263 const char *p, const char *filename, int line_num)
1269 get_arg(arg, sizeof(arg), &p);
1270 if (strcasecmp(arg, "allow") == 0)
1271 acl.action = IP_ALLOW;
1272 else if (strcasecmp(arg, "deny") == 0)
1273 acl.action = IP_DENY;
1275 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1276 filename, line_num, arg);
1280 get_arg(arg, sizeof(arg), &p);
1282 if (resolve_host(&acl.first, arg) != 0) {
1283 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1284 filename, line_num, arg);
1287 acl.last = acl.first;
1289 get_arg(arg, sizeof(arg), &p);
1292 if (resolve_host(&acl.last, arg) != 0) {
1293 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1294 filename, line_num, arg);
1300 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1301 IPAddressACL **naclp = 0;
1307 naclp = &stream->acl;
1313 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1314 filename, line_num);
1320 naclp = &(*naclp)->next;
1328 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1333 IPAddressACL *acl = NULL;
1337 f = fopen(stream->dynamic_acl, "r");
1339 perror(stream->dynamic_acl);
1343 acl = av_mallocz(sizeof(IPAddressACL));
1347 if (fgets(line, sizeof(line), f) == NULL)
1353 if (*p == '\0' || *p == '#')
1355 get_arg(cmd, sizeof(cmd), &p);
1357 if (!strcasecmp(cmd, "ACL"))
1358 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1365 static void free_acl_list(IPAddressACL *in_acl)
1367 IPAddressACL *pacl,*pacl2;
1377 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1379 enum IPAddressAction last_action = IP_DENY;
1381 struct in_addr *src = &c->from_addr.sin_addr;
1382 unsigned long src_addr = src->s_addr;
1384 for (acl = in_acl; acl; acl = acl->next) {
1385 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1386 return (acl->action == IP_ALLOW) ? 1 : 0;
1387 last_action = acl->action;
1390 /* Nothing matched, so return not the last action */
1391 return (last_action == IP_DENY) ? 1 : 0;
1394 static int validate_acl(FFStream *stream, HTTPContext *c)
1400 /* if stream->acl is null validate_acl_list will return 1 */
1401 ret = validate_acl_list(stream->acl, c);
1403 if (stream->dynamic_acl[0]) {
1404 acl = parse_dynamic_acl(stream, c);
1406 ret = validate_acl_list(acl, c);
1414 /* compute the real filename of a file by matching it without its
1415 extensions to all the stream filenames */
1416 static void compute_real_filename(char *filename, int max_size)
1423 /* compute filename by matching without the file extensions */
1424 av_strlcpy(file1, filename, sizeof(file1));
1425 p = strrchr(file1, '.');
1428 for(stream = first_stream; stream != NULL; stream = stream->next) {
1429 av_strlcpy(file2, stream->filename, sizeof(file2));
1430 p = strrchr(file2, '.');
1433 if (!strcmp(file1, file2)) {
1434 av_strlcpy(filename, stream->filename, max_size);
1449 /* parse http request and prepare header */
1450 static int http_parse_request(HTTPContext *c)
1453 enum RedirType redir_type;
1455 char info[1024], filename[1024];
1459 const char *mime_type;
1463 char *useragent = 0;
1466 get_word(cmd, sizeof(cmd), (const char **)&p);
1467 av_strlcpy(c->method, cmd, sizeof(c->method));
1469 if (!strcmp(cmd, "GET"))
1471 else if (!strcmp(cmd, "POST"))
1476 get_word(url, sizeof(url), (const char **)&p);
1477 av_strlcpy(c->url, url, sizeof(c->url));
1479 get_word(protocol, sizeof(protocol), (const char **)&p);
1480 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1483 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1486 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1488 /* find the filename and the optional info string in the request */
1489 p = strchr(url, '?');
1491 av_strlcpy(info, p, sizeof(info));
1496 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1498 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1499 if (strncasecmp(p, "User-Agent:", 11) == 0) {
1501 if (*useragent && *useragent != '\n' && isspace(*useragent))
1505 p = strchr(p, '\n');
1512 redir_type = REDIR_NONE;
1513 if (av_match_ext(filename, "asx")) {
1514 redir_type = REDIR_ASX;
1515 filename[strlen(filename)-1] = 'f';
1516 } else if (av_match_ext(filename, "asf") &&
1517 (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1518 /* if this isn't WMP or lookalike, return the redirector file */
1519 redir_type = REDIR_ASF;
1520 } else if (av_match_ext(filename, "rpm,ram")) {
1521 redir_type = REDIR_RAM;
1522 strcpy(filename + strlen(filename)-2, "m");
1523 } else if (av_match_ext(filename, "rtsp")) {
1524 redir_type = REDIR_RTSP;
1525 compute_real_filename(filename, sizeof(filename) - 1);
1526 } else if (av_match_ext(filename, "sdp")) {
1527 redir_type = REDIR_SDP;
1528 compute_real_filename(filename, sizeof(filename) - 1);
1531 // "redirect" / request to index.html
1532 if (!strlen(filename))
1533 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1535 stream = first_stream;
1536 while (stream != NULL) {
1537 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1539 stream = stream->next;
1541 if (stream == NULL) {
1542 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1543 http_log("File '%s' not found\n", url);
1548 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1549 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1551 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1552 c->http_error = 301;
1554 q += snprintf(q, c->buffer_size,
1555 "HTTP/1.0 301 Moved\r\n"
1557 "Content-type: text/html\r\n"
1559 "<html><head><title>Moved</title></head><body>\r\n"
1560 "You should be <a href=\"%s\">redirected</a>.\r\n"
1561 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1562 /* prepare output buffer */
1563 c->buffer_ptr = c->buffer;
1565 c->state = HTTPSTATE_SEND_HEADER;
1569 /* If this is WMP, get the rate information */
1570 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1571 if (modify_current_stream(c, ratebuf)) {
1572 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1573 if (c->switch_feed_streams[i] >= 0)
1574 c->switch_feed_streams[i] = -1;
1579 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1580 current_bandwidth += stream->bandwidth;
1582 /* If already streaming this feed, do not let start another feeder. */
1583 if (stream->feed_opened) {
1584 snprintf(msg, sizeof(msg), "This feed is already being received.");
1585 http_log("Feed '%s' already being received\n", stream->feed_filename);
1589 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1590 c->http_error = 503;
1592 q += snprintf(q, c->buffer_size,
1593 "HTTP/1.0 503 Server too busy\r\n"
1594 "Content-type: text/html\r\n"
1596 "<html><head><title>Too busy</title></head><body>\r\n"
1597 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1598 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1599 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1600 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1601 /* prepare output buffer */
1602 c->buffer_ptr = c->buffer;
1604 c->state = HTTPSTATE_SEND_HEADER;
1608 if (redir_type != REDIR_NONE) {
1611 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1612 if (strncasecmp(p, "Host:", 5) == 0) {
1616 p = strchr(p, '\n');
1627 while (isspace(*hostinfo))
1630 eoh = strchr(hostinfo, '\n');
1632 if (eoh[-1] == '\r')
1635 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1636 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1637 hostbuf[eoh - hostinfo] = 0;
1639 c->http_error = 200;
1641 switch(redir_type) {
1643 q += snprintf(q, c->buffer_size,
1644 "HTTP/1.0 200 ASX Follows\r\n"
1645 "Content-type: video/x-ms-asf\r\n"
1647 "<ASX Version=\"3\">\r\n"
1648 //"<!-- Autogenerated by ffserver -->\r\n"
1649 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1650 "</ASX>\r\n", hostbuf, filename, info);
1653 q += snprintf(q, c->buffer_size,
1654 "HTTP/1.0 200 RAM Follows\r\n"
1655 "Content-type: audio/x-pn-realaudio\r\n"
1657 "# Autogenerated by ffserver\r\n"
1658 "http://%s/%s%s\r\n", hostbuf, filename, info);
1661 q += snprintf(q, c->buffer_size,
1662 "HTTP/1.0 200 ASF Redirect follows\r\n"
1663 "Content-type: video/x-ms-asf\r\n"
1666 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1670 char hostname[256], *p;
1671 /* extract only hostname */
1672 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1673 p = strrchr(hostname, ':');
1676 q += snprintf(q, c->buffer_size,
1677 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1678 /* XXX: incorrect mime type ? */
1679 "Content-type: application/x-rtsp\r\n"
1681 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1687 int sdp_data_size, len;
1688 struct sockaddr_in my_addr;
1690 q += snprintf(q, c->buffer_size,
1691 "HTTP/1.0 200 OK\r\n"
1692 "Content-type: application/sdp\r\n"
1695 len = sizeof(my_addr);
1696 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1698 /* XXX: should use a dynamic buffer */
1699 sdp_data_size = prepare_sdp_description(stream,
1702 if (sdp_data_size > 0) {
1703 memcpy(q, sdp_data, sdp_data_size);
1715 /* prepare output buffer */
1716 c->buffer_ptr = c->buffer;
1718 c->state = HTTPSTATE_SEND_HEADER;
1724 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1728 stream->conns_served++;
1730 /* XXX: add there authenticate and IP match */
1733 /* if post, it means a feed is being sent */
1734 if (!stream->is_feed) {
1735 /* However it might be a status report from WMP! Let us log the
1736 * data as it might come in handy one day. */
1740 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1741 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1745 if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1746 client_id = strtol(p + 18, 0, 10);
1747 p = strchr(p, '\n');
1755 char *eol = strchr(logline, '\n');
1760 if (eol[-1] == '\r')
1762 http_log("%.*s\n", (int) (eol - logline), logline);
1763 c->suppress_log = 1;
1768 http_log("\nGot request:\n%s\n", c->buffer);
1771 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1774 /* Now we have to find the client_id */
1775 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1776 if (wmpc->wmp_client_id == client_id)
1780 if (wmpc && modify_current_stream(wmpc, ratebuf))
1781 wmpc->switch_pending = 1;
1784 snprintf(msg, sizeof(msg), "POST command not handled");
1788 if (http_start_receive_data(c) < 0) {
1789 snprintf(msg, sizeof(msg), "could not open feed");
1793 c->state = HTTPSTATE_RECEIVE_DATA;
1798 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1799 http_log("\nGot request:\n%s\n", c->buffer);
1802 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1805 /* open input stream */
1806 if (open_input_stream(c, info) < 0) {
1807 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1811 /* prepare http header */
1813 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1814 mime_type = c->stream->fmt->mime_type;
1816 mime_type = "application/x-octet-stream";
1817 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1819 /* for asf, we need extra headers */
1820 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1821 /* Need to allocate a client id */
1823 c->wmp_client_id = av_lfg_get(&random_state);
1825 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);
1827 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1828 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1830 /* prepare output buffer */
1832 c->buffer_ptr = c->buffer;
1834 c->state = HTTPSTATE_SEND_HEADER;
1837 c->http_error = 404;
1839 q += snprintf(q, c->buffer_size,
1840 "HTTP/1.0 404 Not Found\r\n"
1841 "Content-type: text/html\r\n"
1844 "<head><title>404 Not Found</title></head>\n"
1847 /* prepare output buffer */
1848 c->buffer_ptr = c->buffer;
1850 c->state = HTTPSTATE_SEND_HEADER;
1854 c->http_error = 200; /* horrible : we use this value to avoid
1855 going to the send data state */
1856 c->state = HTTPSTATE_SEND_HEADER;
1860 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1862 static const char *suffix = " kMGTP";
1865 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1867 avio_printf(pb, "%"PRId64"%c", count, *s);
1870 static void compute_status(HTTPContext *c)
1879 if (avio_open_dyn_buf(&pb) < 0) {
1880 /* XXX: return an error ? */
1881 c->buffer_ptr = c->buffer;
1882 c->buffer_end = c->buffer;
1886 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1887 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1888 avio_printf(pb, "Pragma: no-cache\r\n");
1889 avio_printf(pb, "\r\n");
1891 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1892 if (c->stream->feed_filename[0])
1893 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1894 avio_printf(pb, "</head>\n<body>");
1895 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1897 avio_printf(pb, "<h2>Available Streams</h2>\n");
1898 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1899 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");
1900 stream = first_stream;
1901 while (stream != NULL) {
1902 char sfilename[1024];
1905 if (stream->feed != stream) {
1906 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1907 eosf = sfilename + strlen(sfilename);
1908 if (eosf - sfilename >= 4) {
1909 if (strcmp(eosf - 4, ".asf") == 0)
1910 strcpy(eosf - 4, ".asx");
1911 else if (strcmp(eosf - 3, ".rm") == 0)
1912 strcpy(eosf - 3, ".ram");
1913 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1914 /* generate a sample RTSP director if
1915 unicast. Generate an SDP redirector if
1917 eosf = strrchr(sfilename, '.');
1919 eosf = sfilename + strlen(sfilename);
1920 if (stream->is_multicast)
1921 strcpy(eosf, ".sdp");
1923 strcpy(eosf, ".rtsp");
1927 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1928 sfilename, stream->filename);
1929 avio_printf(pb, "<td align=right> %d <td align=right> ",
1930 stream->conns_served);
1931 fmt_bytecount(pb, stream->bytes_served);
1932 switch(stream->stream_type) {
1933 case STREAM_TYPE_LIVE: {
1934 int audio_bit_rate = 0;
1935 int video_bit_rate = 0;
1936 const char *audio_codec_name = "";
1937 const char *video_codec_name = "";
1938 const char *audio_codec_name_extra = "";
1939 const char *video_codec_name_extra = "";
1941 for(i=0;i<stream->nb_streams;i++) {
1942 AVStream *st = stream->streams[i];
1943 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1944 switch(st->codec->codec_type) {
1945 case AVMEDIA_TYPE_AUDIO:
1946 audio_bit_rate += st->codec->bit_rate;
1948 if (*audio_codec_name)
1949 audio_codec_name_extra = "...";
1950 audio_codec_name = codec->name;
1953 case AVMEDIA_TYPE_VIDEO:
1954 video_bit_rate += st->codec->bit_rate;
1956 if (*video_codec_name)
1957 video_codec_name_extra = "...";
1958 video_codec_name = codec->name;
1961 case AVMEDIA_TYPE_DATA:
1962 video_bit_rate += st->codec->bit_rate;
1968 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",
1971 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1972 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1974 avio_printf(pb, "<td>%s", stream->feed->filename);
1976 avio_printf(pb, "<td>%s", stream->feed_filename);
1977 avio_printf(pb, "\n");
1981 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1985 stream = stream->next;
1987 avio_printf(pb, "</table>\n");
1989 stream = first_stream;
1990 while (stream != NULL) {
1991 if (stream->feed == stream) {
1992 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1994 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1996 #if defined(linux) && !defined(CONFIG_NOCUTILS)
2001 /* This is somewhat linux specific I guess */
2002 snprintf(ps_cmd, sizeof(ps_cmd),
2003 "ps -o \"%%cpu,cputime\" --no-headers %d",
2006 pid_stat = popen(ps_cmd, "r");
2011 if (fscanf(pid_stat, "%10s %64s", cpuperc,
2013 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2021 avio_printf(pb, "<p>");
2023 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");
2025 for (i = 0; i < stream->nb_streams; i++) {
2026 AVStream *st = stream->streams[i];
2027 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2028 const char *type = "unknown";
2029 char parameters[64];
2033 switch(st->codec->codec_type) {
2034 case AVMEDIA_TYPE_AUDIO:
2036 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2038 case AVMEDIA_TYPE_VIDEO:
2040 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2041 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2046 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2047 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2049 avio_printf(pb, "</table>\n");
2052 stream = stream->next;
2055 /* connection status */
2056 avio_printf(pb, "<h2>Connection Status</h2>\n");
2058 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2059 nb_connections, nb_max_connections);
2061 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2062 current_bandwidth, max_bandwidth);
2064 avio_printf(pb, "<table>\n");
2065 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");
2066 c1 = first_http_ctx;
2068 while (c1 != NULL) {
2074 for (j = 0; j < c1->stream->nb_streams; j++) {
2075 if (!c1->stream->feed)
2076 bitrate += c1->stream->streams[j]->codec->bit_rate;
2077 else if (c1->feed_streams[j] >= 0)
2078 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2083 p = inet_ntoa(c1->from_addr.sin_addr);
2084 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2086 c1->stream ? c1->stream->filename : "",
2087 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2090 http_state[c1->state]);
2091 fmt_bytecount(pb, bitrate);
2092 avio_printf(pb, "<td align=right>");
2093 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2094 avio_printf(pb, "<td align=right>");
2095 fmt_bytecount(pb, c1->data_count);
2096 avio_printf(pb, "\n");
2099 avio_printf(pb, "</table>\n");
2104 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2105 avio_printf(pb, "</body>\n</html>\n");
2107 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2108 c->buffer_ptr = c->pb_buffer;
2109 c->buffer_end = c->pb_buffer + len;
2112 /* check if the parser needs to be opened for stream i */
2113 static void open_parser(AVFormatContext *s, int i)
2115 AVStream *st = s->streams[i];
2118 if (!st->codec->codec) {
2119 codec = avcodec_find_decoder(st->codec->codec_id);
2120 if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2121 st->codec->parse_only = 1;
2122 if (avcodec_open(st->codec, codec) < 0)
2123 st->codec->parse_only = 0;
2128 static int open_input_stream(HTTPContext *c, const char *info)
2131 char input_filename[1024];
2133 int buf_size, i, ret;
2136 /* find file name */
2137 if (c->stream->feed) {
2138 strcpy(input_filename, c->stream->feed->feed_filename);
2139 buf_size = FFM_PACKET_SIZE;
2140 /* compute position (absolute time) */
2141 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2142 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2144 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2145 int prebuffer = strtol(buf, 0, 10);
2146 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2148 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2150 strcpy(input_filename, c->stream->feed_filename);
2152 /* compute position (relative time) */
2153 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2154 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2159 if (input_filename[0] == '\0')
2163 if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
2164 buf_size, c->stream->ap_in)) < 0) {
2165 http_log("could not open %s: %d\n", input_filename, ret);
2168 s->flags |= AVFMT_FLAG_GENPTS;
2170 if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2171 http_log("Could not find stream info '%s'\n", input_filename);
2172 av_close_input_file(s);
2176 /* open each parser */
2177 for(i=0;i<s->nb_streams;i++)
2180 /* choose stream as clock source (we favorize video stream if
2181 present) for packet sending */
2182 c->pts_stream_index = 0;
2183 for(i=0;i<c->stream->nb_streams;i++) {
2184 if (c->pts_stream_index == 0 &&
2185 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2186 c->pts_stream_index = i;
2191 if (c->fmt_in->iformat->read_seek)
2192 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2194 /* set the start time (needed for maxtime and RTP packet timing) */
2195 c->start_time = cur_time;
2196 c->first_pts = AV_NOPTS_VALUE;
2200 /* return the server clock (in us) */
2201 static int64_t get_server_clock(HTTPContext *c)
2203 /* compute current pts value from system time */
2204 return (cur_time - c->start_time) * 1000;
2207 /* return the estimated time at which the current packet must be sent
2209 static int64_t get_packet_send_clock(HTTPContext *c)
2211 int bytes_left, bytes_sent, frame_bytes;
2213 frame_bytes = c->cur_frame_bytes;
2214 if (frame_bytes <= 0)
2217 bytes_left = c->buffer_end - c->buffer_ptr;
2218 bytes_sent = frame_bytes - bytes_left;
2219 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2224 static int http_prepare_data(HTTPContext *c)
2227 AVFormatContext *ctx;
2229 av_freep(&c->pb_buffer);
2231 case HTTPSTATE_SEND_DATA_HEADER:
2232 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2233 av_metadata_set2(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2234 av_metadata_set2(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2235 av_metadata_set2(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2236 av_metadata_set2(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2238 for(i=0;i<c->stream->nb_streams;i++) {
2241 st = av_mallocz(sizeof(AVStream));
2242 c->fmt_ctx.streams[i] = st;
2243 /* if file or feed, then just take streams from FFStream struct */
2244 if (!c->stream->feed ||
2245 c->stream->feed == c->stream)
2246 src = c->stream->streams[i];
2248 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2252 st->codec->frame_number = 0; /* XXX: should be done in
2253 AVStream, not in codec */
2255 /* set output format parameters */
2256 c->fmt_ctx.oformat = c->stream->fmt;
2257 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2259 c->got_key_frame = 0;
2261 /* prepare header and save header data in a stream */
2262 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2263 /* XXX: potential leak */
2266 c->fmt_ctx.pb->seekable = 0;
2269 * HACK to avoid mpeg ps muxer to spit many underflow errors
2270 * Default value from FFmpeg
2271 * Try to set it use configuration option
2273 c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
2274 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2276 av_set_parameters(&c->fmt_ctx, NULL);
2277 if (av_write_header(&c->fmt_ctx) < 0) {
2278 http_log("Error writing output header\n");
2281 av_metadata_free(&c->fmt_ctx.metadata);
2283 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2284 c->buffer_ptr = c->pb_buffer;
2285 c->buffer_end = c->pb_buffer + len;
2287 c->state = HTTPSTATE_SEND_DATA;
2288 c->last_packet_sent = 0;
2290 case HTTPSTATE_SEND_DATA:
2291 /* find a new packet */
2292 /* read a packet from the input stream */
2293 if (c->stream->feed)
2294 ffm_set_write_index(c->fmt_in,
2295 c->stream->feed->feed_write_index,
2296 c->stream->feed->feed_size);
2298 if (c->stream->max_time &&
2299 c->stream->max_time + c->start_time - cur_time < 0)
2300 /* We have timed out */
2301 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2305 ret = av_read_frame(c->fmt_in, &pkt);
2307 if (c->stream->feed) {
2308 /* if coming from feed, it means we reached the end of the
2309 ffm file, so must wait for more data */
2310 c->state = HTTPSTATE_WAIT_FEED;
2311 return 1; /* state changed */
2312 } else if (ret == AVERROR(EAGAIN)) {
2313 /* input not ready, come back later */
2316 if (c->stream->loop) {
2317 av_close_input_file(c->fmt_in);
2319 if (open_input_stream(c, "") < 0)
2324 /* must send trailer now because eof or error */
2325 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2329 int source_index = pkt.stream_index;
2330 /* update first pts if needed */
2331 if (c->first_pts == AV_NOPTS_VALUE) {
2332 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2333 c->start_time = cur_time;
2335 /* send it to the appropriate stream */
2336 if (c->stream->feed) {
2337 /* if coming from a feed, select the right stream */
2338 if (c->switch_pending) {
2339 c->switch_pending = 0;
2340 for(i=0;i<c->stream->nb_streams;i++) {
2341 if (c->switch_feed_streams[i] == pkt.stream_index)
2342 if (pkt.flags & AV_PKT_FLAG_KEY)
2343 c->switch_feed_streams[i] = -1;
2344 if (c->switch_feed_streams[i] >= 0)
2345 c->switch_pending = 1;
2348 for(i=0;i<c->stream->nb_streams;i++) {
2349 if (c->stream->feed_streams[i] == pkt.stream_index) {
2350 AVStream *st = c->fmt_in->streams[source_index];
2351 pkt.stream_index = i;
2352 if (pkt.flags & AV_PKT_FLAG_KEY &&
2353 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2354 c->stream->nb_streams == 1))
2355 c->got_key_frame = 1;
2356 if (!c->stream->send_on_key || c->got_key_frame)
2361 AVCodecContext *codec;
2362 AVStream *ist, *ost;
2364 ist = c->fmt_in->streams[source_index];
2365 /* specific handling for RTP: we use several
2366 output stream (one for each RTP
2367 connection). XXX: need more abstract handling */
2368 if (c->is_packetized) {
2369 /* compute send time and duration */
2370 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2371 c->cur_pts -= c->first_pts;
2372 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2373 /* find RTP context */
2374 c->packet_stream_index = pkt.stream_index;
2375 ctx = c->rtp_ctx[c->packet_stream_index];
2377 av_free_packet(&pkt);
2380 codec = ctx->streams[0]->codec;
2381 /* only one stream per RTP connection */
2382 pkt.stream_index = 0;
2386 codec = ctx->streams[pkt.stream_index]->codec;
2389 if (c->is_packetized) {
2390 int max_packet_size;
2391 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2392 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2394 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2395 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2397 ret = avio_open_dyn_buf(&ctx->pb);
2400 /* XXX: potential leak */
2403 ost = ctx->streams[pkt.stream_index];
2405 ctx->pb->seekable = 0;
2406 if (pkt.dts != AV_NOPTS_VALUE)
2407 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2408 if (pkt.pts != AV_NOPTS_VALUE)
2409 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2410 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2411 if (av_write_frame(ctx, &pkt) < 0) {
2412 http_log("Error writing frame to output\n");
2413 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2416 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2417 c->cur_frame_bytes = len;
2418 c->buffer_ptr = c->pb_buffer;
2419 c->buffer_end = c->pb_buffer + len;
2421 codec->frame_number++;
2423 av_free_packet(&pkt);
2427 av_free_packet(&pkt);
2432 case HTTPSTATE_SEND_DATA_TRAILER:
2433 /* last packet test ? */
2434 if (c->last_packet_sent || c->is_packetized)
2437 /* prepare header */
2438 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2439 /* XXX: potential leak */
2442 c->fmt_ctx.pb->seekable = 0;
2443 av_write_trailer(ctx);
2444 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2445 c->buffer_ptr = c->pb_buffer;
2446 c->buffer_end = c->pb_buffer + len;
2448 c->last_packet_sent = 1;
2454 /* should convert the format at the same time */
2455 /* send data starting at c->buffer_ptr to the output connection
2456 (either UDP or TCP connection) */
2457 static int http_send_data(HTTPContext *c)
2462 if (c->buffer_ptr >= c->buffer_end) {
2463 ret = http_prepare_data(c);
2467 /* state change requested */
2470 if (c->is_packetized) {
2471 /* RTP data output */
2472 len = c->buffer_end - c->buffer_ptr;
2474 /* fail safe - should never happen */
2476 c->buffer_ptr = c->buffer_end;
2479 len = (c->buffer_ptr[0] << 24) |
2480 (c->buffer_ptr[1] << 16) |
2481 (c->buffer_ptr[2] << 8) |
2483 if (len > (c->buffer_end - c->buffer_ptr))
2485 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2486 /* nothing to send yet: we can wait */
2490 c->data_count += len;
2491 update_datarate(&c->datarate, c->data_count);
2493 c->stream->bytes_served += len;
2495 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2496 /* RTP packets are sent inside the RTSP TCP connection */
2498 int interleaved_index, size;
2500 HTTPContext *rtsp_c;
2503 /* if no RTSP connection left, error */
2506 /* if already sending something, then wait. */
2507 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2509 if (avio_open_dyn_buf(&pb) < 0)
2511 interleaved_index = c->packet_stream_index * 2;
2512 /* RTCP packets are sent at odd indexes */
2513 if (c->buffer_ptr[1] == 200)
2514 interleaved_index++;
2515 /* write RTSP TCP header */
2517 header[1] = interleaved_index;
2518 header[2] = len >> 8;
2520 avio_write(pb, header, 4);
2521 /* write RTP packet data */
2523 avio_write(pb, c->buffer_ptr, len);
2524 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2525 /* prepare asynchronous TCP sending */
2526 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2527 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2528 c->buffer_ptr += len;
2530 /* send everything we can NOW */
2531 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2532 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2534 rtsp_c->packet_buffer_ptr += len;
2535 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2536 /* if we could not send all the data, we will
2537 send it later, so a new state is needed to
2538 "lock" the RTSP TCP connection */
2539 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2542 /* all data has been sent */
2543 av_freep(&c->packet_buffer);
2545 /* send RTP packet directly in UDP */
2547 url_write(c->rtp_handles[c->packet_stream_index],
2548 c->buffer_ptr, len);
2549 c->buffer_ptr += len;
2550 /* here we continue as we can send several packets per 10 ms slot */
2553 /* TCP data output */
2554 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2556 if (ff_neterrno() != AVERROR(EAGAIN) &&
2557 ff_neterrno() != AVERROR(EINTR))
2558 /* error : close connection */
2563 c->buffer_ptr += len;
2565 c->data_count += len;
2566 update_datarate(&c->datarate, c->data_count);
2568 c->stream->bytes_served += len;
2576 static int http_start_receive_data(HTTPContext *c)
2580 if (c->stream->feed_opened)
2583 /* Don't permit writing to this one */
2584 if (c->stream->readonly)
2588 fd = open(c->stream->feed_filename, O_RDWR);
2590 http_log("Error opening feeder file: %s\n", strerror(errno));
2595 if (c->stream->truncate) {
2596 /* truncate feed file */
2597 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2598 ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2599 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2601 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2602 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2607 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2608 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2609 lseek(fd, 0, SEEK_SET);
2611 /* init buffer input */
2612 c->buffer_ptr = c->buffer;
2613 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2614 c->stream->feed_opened = 1;
2615 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2619 static int http_receive_data(HTTPContext *c)
2622 int len, loop_run = 0;
2624 while (c->chunked_encoding && !c->chunk_size &&
2625 c->buffer_end > c->buffer_ptr) {
2626 /* read chunk header, if present */
2627 len = recv(c->fd, c->buffer_ptr, 1, 0);
2630 if (ff_neterrno() != AVERROR(EAGAIN) &&
2631 ff_neterrno() != AVERROR(EINTR))
2632 /* error : close connection */
2635 } else if (len == 0) {
2636 /* end of connection : close it */
2638 } else if (c->buffer_ptr - c->buffer >= 2 &&
2639 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2640 c->chunk_size = strtol(c->buffer, 0, 16);
2641 if (c->chunk_size == 0) // end of stream
2643 c->buffer_ptr = c->buffer;
2645 } else if (++loop_run > 10) {
2646 /* no chunk header, abort */
2653 if (c->buffer_end > c->buffer_ptr) {
2654 len = recv(c->fd, c->buffer_ptr,
2655 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2657 if (ff_neterrno() != AVERROR(EAGAIN) &&
2658 ff_neterrno() != AVERROR(EINTR))
2659 /* error : close connection */
2661 } else if (len == 0)
2662 /* end of connection : close it */
2665 c->chunk_size -= len;
2666 c->buffer_ptr += len;
2667 c->data_count += len;
2668 update_datarate(&c->datarate, c->data_count);
2672 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2673 if (c->buffer[0] != 'f' ||
2674 c->buffer[1] != 'm') {
2675 http_log("Feed stream has become desynchronized -- disconnecting\n");
2680 if (c->buffer_ptr >= c->buffer_end) {
2681 FFStream *feed = c->stream;
2682 /* a packet has been received : write it in the store, except
2684 if (c->data_count > FFM_PACKET_SIZE) {
2686 // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2687 /* XXX: use llseek or url_seek */
2688 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2689 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2690 http_log("Error writing to feed file: %s\n", strerror(errno));
2694 feed->feed_write_index += FFM_PACKET_SIZE;
2695 /* update file size */
2696 if (feed->feed_write_index > c->stream->feed_size)
2697 feed->feed_size = feed->feed_write_index;
2699 /* handle wrap around if max file size reached */
2700 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2701 feed->feed_write_index = FFM_PACKET_SIZE;
2704 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2705 http_log("Error writing index to feed file: %s\n", strerror(errno));
2709 /* wake up any waiting connections */
2710 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2711 if (c1->state == HTTPSTATE_WAIT_FEED &&
2712 c1->stream->feed == c->stream->feed)
2713 c1->state = HTTPSTATE_SEND_DATA;
2716 /* We have a header in our hands that contains useful data */
2717 AVFormatContext *s = NULL;
2719 AVInputFormat *fmt_in;
2722 /* use feed output format name to find corresponding input format */
2723 fmt_in = av_find_input_format(feed->fmt->name);
2727 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2728 0, NULL, NULL, NULL, NULL);
2731 if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2736 /* Now we have the actual streams */
2737 if (s->nb_streams != feed->nb_streams) {
2738 av_close_input_stream(s);
2740 http_log("Feed '%s' stream number does not match registered feed\n",
2741 c->stream->feed_filename);
2745 for (i = 0; i < s->nb_streams; i++) {
2746 AVStream *fst = feed->streams[i];
2747 AVStream *st = s->streams[i];
2748 avcodec_copy_context(fst->codec, st->codec);
2751 av_close_input_stream(s);
2754 c->buffer_ptr = c->buffer;
2759 c->stream->feed_opened = 0;
2761 /* wake up any waiting connections to stop waiting for feed */
2762 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2763 if (c1->state == HTTPSTATE_WAIT_FEED &&
2764 c1->stream->feed == c->stream->feed)
2765 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2770 /********************************************************************/
2773 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2780 switch(error_number) {
2781 case RTSP_STATUS_OK:
2784 case RTSP_STATUS_METHOD:
2785 str = "Method Not Allowed";
2787 case RTSP_STATUS_BANDWIDTH:
2788 str = "Not Enough Bandwidth";
2790 case RTSP_STATUS_SESSION:
2791 str = "Session Not Found";
2793 case RTSP_STATUS_STATE:
2794 str = "Method Not Valid in This State";
2796 case RTSP_STATUS_AGGREGATE:
2797 str = "Aggregate operation not allowed";
2799 case RTSP_STATUS_ONLY_AGGREGATE:
2800 str = "Only aggregate operation allowed";
2802 case RTSP_STATUS_TRANSPORT:
2803 str = "Unsupported transport";
2805 case RTSP_STATUS_INTERNAL:
2806 str = "Internal Server Error";
2808 case RTSP_STATUS_SERVICE:
2809 str = "Service Unavailable";
2811 case RTSP_STATUS_VERSION:
2812 str = "RTSP Version not supported";
2815 str = "Unknown Error";
2819 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2820 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2822 /* output GMT time */
2825 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2826 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2829 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2831 rtsp_reply_header(c, error_number);
2832 avio_printf(c->pb, "\r\n");
2835 static int rtsp_parse_request(HTTPContext *c)
2837 const char *p, *p1, *p2;
2843 RTSPMessageHeader header1, *header = &header1;
2845 c->buffer_ptr[0] = '\0';
2848 get_word(cmd, sizeof(cmd), &p);
2849 get_word(url, sizeof(url), &p);
2850 get_word(protocol, sizeof(protocol), &p);
2852 av_strlcpy(c->method, cmd, sizeof(c->method));
2853 av_strlcpy(c->url, url, sizeof(c->url));
2854 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2856 if (avio_open_dyn_buf(&c->pb) < 0) {
2857 /* XXX: cannot do more */
2858 c->pb = NULL; /* safety */
2862 /* check version name */
2863 if (strcmp(protocol, "RTSP/1.0") != 0) {
2864 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2868 /* parse each header line */
2869 memset(header, 0, sizeof(*header));
2870 /* skip to next line */
2871 while (*p != '\n' && *p != '\0')
2875 while (*p != '\0') {
2876 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2880 if (p2 > p && p2[-1] == '\r')
2882 /* skip empty line */
2886 if (len > sizeof(line) - 1)
2887 len = sizeof(line) - 1;
2888 memcpy(line, p, len);
2890 ff_rtsp_parse_line(header, line, NULL, NULL);
2894 /* handle sequence number */
2895 c->seq = header->seq;
2897 if (!strcmp(cmd, "DESCRIBE"))
2898 rtsp_cmd_describe(c, url);
2899 else if (!strcmp(cmd, "OPTIONS"))
2900 rtsp_cmd_options(c, url);
2901 else if (!strcmp(cmd, "SETUP"))
2902 rtsp_cmd_setup(c, url, header);
2903 else if (!strcmp(cmd, "PLAY"))
2904 rtsp_cmd_play(c, url, header);
2905 else if (!strcmp(cmd, "PAUSE"))
2906 rtsp_cmd_pause(c, url, header);
2907 else if (!strcmp(cmd, "TEARDOWN"))
2908 rtsp_cmd_teardown(c, url, header);
2910 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2913 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2914 c->pb = NULL; /* safety */
2916 /* XXX: cannot do more */
2919 c->buffer_ptr = c->pb_buffer;
2920 c->buffer_end = c->pb_buffer + len;
2921 c->state = RTSPSTATE_SEND_REPLY;
2925 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2926 struct in_addr my_ip)
2928 AVFormatContext *avc;
2929 AVStream *avs = NULL;
2932 avc = avformat_alloc_context();
2936 av_metadata_set2(&avc->metadata, "title",
2937 stream->title[0] ? stream->title : "No Title", 0);
2938 avc->nb_streams = stream->nb_streams;
2939 if (stream->is_multicast) {
2940 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2941 inet_ntoa(stream->multicast_ip),
2942 stream->multicast_port, stream->multicast_ttl);
2944 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2947 #if !FF_API_MAX_STREAMS
2948 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2949 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2952 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2953 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2956 for(i = 0; i < stream->nb_streams; i++) {
2957 avc->streams[i] = &avs[i];
2958 avc->streams[i]->codec = stream->streams[i]->codec;
2960 *pbuffer = av_mallocz(2048);
2961 av_sdp_create(&avc, 1, *pbuffer, 2048);
2964 #if !FF_API_MAX_STREAMS
2965 av_free(avc->streams);
2967 av_metadata_free(&avc->metadata);
2971 return strlen(*pbuffer);
2974 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2976 // rtsp_reply_header(c, RTSP_STATUS_OK);
2977 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2978 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2979 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2980 avio_printf(c->pb, "\r\n");
2983 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2989 int content_length, len;
2990 struct sockaddr_in my_addr;
2992 /* find which url is asked */
2993 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2998 for(stream = first_stream; stream != NULL; stream = stream->next) {
2999 if (!stream->is_feed &&
3000 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3001 !strcmp(path, stream->filename)) {
3005 /* no stream found */
3006 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3010 /* prepare the media description in sdp format */
3012 /* get the host IP */
3013 len = sizeof(my_addr);
3014 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3015 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3016 if (content_length < 0) {
3017 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3020 rtsp_reply_header(c, RTSP_STATUS_OK);
3021 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3022 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3023 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3024 avio_printf(c->pb, "\r\n");
3025 avio_write(c->pb, content, content_length);
3029 static HTTPContext *find_rtp_session(const char *session_id)
3033 if (session_id[0] == '\0')
3036 for(c = first_http_ctx; c != NULL; c = c->next) {
3037 if (!strcmp(c->session_id, session_id))
3043 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3045 RTSPTransportField *th;
3048 for(i=0;i<h->nb_transports;i++) {
3049 th = &h->transports[i];
3050 if (th->lower_transport == lower_transport)
3056 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3057 RTSPMessageHeader *h)
3060 int stream_index, rtp_port, rtcp_port;
3065 RTSPTransportField *th;
3066 struct sockaddr_in dest_addr;
3067 RTSPActionServerSetup setup;
3069 /* find which url is asked */
3070 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3075 /* now check each stream */
3076 for(stream = first_stream; stream != NULL; stream = stream->next) {
3077 if (!stream->is_feed &&
3078 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3079 /* accept aggregate filenames only if single stream */
3080 if (!strcmp(path, stream->filename)) {
3081 if (stream->nb_streams != 1) {
3082 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3089 for(stream_index = 0; stream_index < stream->nb_streams;
3091 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3092 stream->filename, stream_index);
3093 if (!strcmp(path, buf))
3098 /* no stream found */
3099 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3103 /* generate session id if needed */
3104 if (h->session_id[0] == '\0')
3105 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3106 av_lfg_get(&random_state), av_lfg_get(&random_state));
3108 /* find rtp session, and create it if none found */
3109 rtp_c = find_rtp_session(h->session_id);
3111 /* always prefer UDP */
3112 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3114 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3116 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3121 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3122 th->lower_transport);
3124 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3128 /* open input stream */
3129 if (open_input_stream(rtp_c, "") < 0) {
3130 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3135 /* test if stream is OK (test needed because several SETUP needs
3136 to be done for a given file) */
3137 if (rtp_c->stream != stream) {
3138 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3142 /* test if stream is already set up */
3143 if (rtp_c->rtp_ctx[stream_index]) {
3144 rtsp_reply_error(c, RTSP_STATUS_STATE);
3148 /* check transport */
3149 th = find_transport(h, rtp_c->rtp_protocol);
3150 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3151 th->client_port_min <= 0)) {
3152 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3156 /* setup default options */
3157 setup.transport_option[0] = '\0';
3158 dest_addr = rtp_c->from_addr;
3159 dest_addr.sin_port = htons(th->client_port_min);
3162 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3163 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3167 /* now everything is OK, so we can send the connection parameters */
3168 rtsp_reply_header(c, RTSP_STATUS_OK);
3170 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3172 switch(rtp_c->rtp_protocol) {
3173 case RTSP_LOWER_TRANSPORT_UDP:
3174 rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3175 rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3176 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3177 "client_port=%d-%d;server_port=%d-%d",
3178 th->client_port_min, th->client_port_max,
3179 rtp_port, rtcp_port);
3181 case RTSP_LOWER_TRANSPORT_TCP:
3182 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3183 stream_index * 2, stream_index * 2 + 1);
3188 if (setup.transport_option[0] != '\0')
3189 avio_printf(c->pb, ";%s", setup.transport_option);
3190 avio_printf(c->pb, "\r\n");
3193 avio_printf(c->pb, "\r\n");
3197 /* find an rtp connection by using the session ID. Check consistency
3199 static HTTPContext *find_rtp_session_with_url(const char *url,
3200 const char *session_id)
3208 rtp_c = find_rtp_session(session_id);
3212 /* find which url is asked */
3213 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3217 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3218 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3219 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3220 rtp_c->stream->filename, s);
3221 if(!strncmp(path, buf, sizeof(buf))) {
3222 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3227 if (len > 0 && path[len - 1] == '/' &&
3228 !strncmp(path, rtp_c->stream->filename, len - 1))
3233 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3237 rtp_c = find_rtp_session_with_url(url, h->session_id);
3239 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3243 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3244 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3245 rtp_c->state != HTTPSTATE_READY) {
3246 rtsp_reply_error(c, RTSP_STATUS_STATE);
3250 rtp_c->state = HTTPSTATE_SEND_DATA;
3252 /* now everything is OK, so we can send the connection parameters */
3253 rtsp_reply_header(c, RTSP_STATUS_OK);
3255 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3256 avio_printf(c->pb, "\r\n");
3259 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3263 rtp_c = find_rtp_session_with_url(url, h->session_id);
3265 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3269 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3270 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3271 rtsp_reply_error(c, RTSP_STATUS_STATE);
3275 rtp_c->state = HTTPSTATE_READY;
3276 rtp_c->first_pts = AV_NOPTS_VALUE;
3277 /* now everything is OK, so we can send the connection parameters */
3278 rtsp_reply_header(c, RTSP_STATUS_OK);
3280 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3281 avio_printf(c->pb, "\r\n");
3284 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3287 char session_id[32];
3289 rtp_c = find_rtp_session_with_url(url, h->session_id);
3291 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3295 av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3297 /* abort the session */
3298 close_connection(rtp_c);
3300 /* now everything is OK, so we can send the connection parameters */
3301 rtsp_reply_header(c, RTSP_STATUS_OK);
3303 avio_printf(c->pb, "Session: %s\r\n", session_id);
3304 avio_printf(c->pb, "\r\n");
3308 /********************************************************************/
3311 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3312 FFStream *stream, const char *session_id,
3313 enum RTSPLowerTransport rtp_protocol)
3315 HTTPContext *c = NULL;
3316 const char *proto_str;
3318 /* XXX: should output a warning page when coming
3319 close to the connection limit */
3320 if (nb_connections >= nb_max_connections)
3323 /* add a new connection */
3324 c = av_mallocz(sizeof(HTTPContext));
3329 c->poll_entry = NULL;
3330 c->from_addr = *from_addr;
3331 c->buffer_size = IOBUFFER_INIT_SIZE;
3332 c->buffer = av_malloc(c->buffer_size);
3337 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3338 c->state = HTTPSTATE_READY;
3339 c->is_packetized = 1;
3340 c->rtp_protocol = rtp_protocol;
3342 /* protocol is shown in statistics */
3343 switch(c->rtp_protocol) {
3344 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3345 proto_str = "MCAST";
3347 case RTSP_LOWER_TRANSPORT_UDP:
3350 case RTSP_LOWER_TRANSPORT_TCP:
3357 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3358 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3360 current_bandwidth += stream->bandwidth;
3362 c->next = first_http_ctx;
3374 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3375 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3377 static int rtp_new_av_stream(HTTPContext *c,
3378 int stream_index, struct sockaddr_in *dest_addr,
3379 HTTPContext *rtsp_c)
3381 AVFormatContext *ctx;
3384 URLContext *h = NULL;
3386 int max_packet_size;
3388 /* now we can open the relevant output stream */
3389 ctx = avformat_alloc_context();
3392 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3394 st = av_mallocz(sizeof(AVStream));
3397 ctx->nb_streams = 1;
3398 ctx->streams[0] = st;
3400 if (!c->stream->feed ||
3401 c->stream->feed == c->stream)
3402 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3405 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3407 st->priv_data = NULL;
3409 /* build destination RTP address */
3410 ipaddr = inet_ntoa(dest_addr->sin_addr);
3412 switch(c->rtp_protocol) {
3413 case RTSP_LOWER_TRANSPORT_UDP:
3414 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3417 /* XXX: also pass as parameter to function ? */
3418 if (c->stream->is_multicast) {
3420 ttl = c->stream->multicast_ttl;
3423 snprintf(ctx->filename, sizeof(ctx->filename),
3424 "rtp://%s:%d?multicast=1&ttl=%d",
3425 ipaddr, ntohs(dest_addr->sin_port), ttl);
3427 snprintf(ctx->filename, sizeof(ctx->filename),
3428 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3431 if (url_open(&h, ctx->filename, AVIO_WRONLY) < 0)
3433 c->rtp_handles[stream_index] = h;
3434 max_packet_size = url_get_max_packet_size(h);
3436 case RTSP_LOWER_TRANSPORT_TCP:
3439 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3445 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3446 ipaddr, ntohs(dest_addr->sin_port),
3447 c->stream->filename, stream_index, c->protocol);
3449 /* normally, no packets should be output here, but the packet size may be checked */
3450 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3451 /* XXX: close stream */
3454 av_set_parameters(ctx, NULL);
3455 if (av_write_header(ctx) < 0) {
3462 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3465 c->rtp_ctx[stream_index] = ctx;
3469 /********************************************************************/
3470 /* ffserver initialization */
3472 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3476 fst = av_mallocz(sizeof(AVStream));
3480 fst->codec= avcodec_alloc_context();
3481 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3482 if (codec->extradata_size) {
3483 fst->codec->extradata = av_malloc(codec->extradata_size);
3484 memcpy(fst->codec->extradata, codec->extradata,
3485 codec->extradata_size);
3488 /* live streams must use the actual feed's codec since it may be
3489 * updated later to carry extradata needed by the streams.
3493 fst->priv_data = av_mallocz(sizeof(FeedData));
3494 fst->index = stream->nb_streams;
3495 av_set_pts_info(fst, 33, 1, 90000);
3496 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3497 stream->streams[stream->nb_streams++] = fst;
3501 /* return the stream number in the feed */
3502 static int add_av_stream(FFStream *feed, AVStream *st)
3505 AVCodecContext *av, *av1;
3509 for(i=0;i<feed->nb_streams;i++) {
3510 st = feed->streams[i];
3512 if (av1->codec_id == av->codec_id &&
3513 av1->codec_type == av->codec_type &&
3514 av1->bit_rate == av->bit_rate) {
3516 switch(av->codec_type) {
3517 case AVMEDIA_TYPE_AUDIO:
3518 if (av1->channels == av->channels &&
3519 av1->sample_rate == av->sample_rate)
3522 case AVMEDIA_TYPE_VIDEO:
3523 if (av1->width == av->width &&
3524 av1->height == av->height &&
3525 av1->time_base.den == av->time_base.den &&
3526 av1->time_base.num == av->time_base.num &&
3527 av1->gop_size == av->gop_size)
3536 fst = add_av_stream1(feed, av, 0);
3539 return feed->nb_streams - 1;
3544 static void remove_stream(FFStream *stream)
3548 while (*ps != NULL) {
3556 /* specific mpeg4 handling : we extract the raw parameters */
3557 static void extract_mpeg4_header(AVFormatContext *infile)
3559 int mpeg4_count, i, size;
3565 for(i=0;i<infile->nb_streams;i++) {
3566 st = infile->streams[i];
3567 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3568 st->codec->extradata_size == 0) {
3575 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3576 while (mpeg4_count > 0) {
3577 if (av_read_packet(infile, &pkt) < 0)
3579 st = infile->streams[pkt.stream_index];
3580 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3581 st->codec->extradata_size == 0) {
3582 av_freep(&st->codec->extradata);
3583 /* fill extradata with the header */
3584 /* XXX: we make hard suppositions here ! */
3586 while (p < pkt.data + pkt.size - 4) {
3587 /* stop when vop header is found */
3588 if (p[0] == 0x00 && p[1] == 0x00 &&
3589 p[2] == 0x01 && p[3] == 0xb6) {
3590 size = p - pkt.data;
3591 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3592 st->codec->extradata = av_malloc(size);
3593 st->codec->extradata_size = size;
3594 memcpy(st->codec->extradata, pkt.data, size);
3601 av_free_packet(&pkt);
3605 /* compute the needed AVStream for each file */
3606 static void build_file_streams(void)
3608 FFStream *stream, *stream_next;
3609 AVFormatContext *infile;
3612 /* gather all streams */
3613 for(stream = first_stream; stream != NULL; stream = stream_next) {
3614 stream_next = stream->next;
3615 if (stream->stream_type == STREAM_TYPE_LIVE &&
3617 /* the stream comes from a file */
3618 /* try to open the file */
3620 stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3621 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3622 /* specific case : if transport stream output to RTP,
3623 we use a raw transport stream reader */
3624 stream->ap_in->mpeg2ts_raw = 1;
3625 stream->ap_in->mpeg2ts_compute_pcr = 1;
3628 http_log("Opening file '%s'\n", stream->feed_filename);
3629 if ((ret = av_open_input_file(&infile, stream->feed_filename,
3630 stream->ifmt, 0, stream->ap_in)) < 0) {
3631 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3632 /* remove stream (no need to spend more time on it) */
3634 remove_stream(stream);
3636 /* find all the AVStreams inside and reference them in
3638 if (av_find_stream_info(infile) < 0) {
3639 http_log("Could not find codec parameters from '%s'\n",
3640 stream->feed_filename);
3641 av_close_input_file(infile);
3644 extract_mpeg4_header(infile);
3646 for(i=0;i<infile->nb_streams;i++)
3647 add_av_stream1(stream, infile->streams[i]->codec, 1);
3649 av_close_input_file(infile);
3655 /* compute the needed AVStream for each feed */
3656 static void build_feed_streams(void)
3658 FFStream *stream, *feed;
3661 /* gather all streams */
3662 for(stream = first_stream; stream != NULL; stream = stream->next) {
3663 feed = stream->feed;
3665 if (!stream->is_feed) {
3666 /* we handle a stream coming from a feed */
3667 for(i=0;i<stream->nb_streams;i++)
3668 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3673 /* gather all streams */
3674 for(stream = first_stream; stream != NULL; stream = stream->next) {
3675 feed = stream->feed;
3677 if (stream->is_feed) {
3678 for(i=0;i<stream->nb_streams;i++)
3679 stream->feed_streams[i] = i;
3684 /* create feed files if needed */
3685 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3688 if (url_exist(feed->feed_filename)) {
3689 /* See if it matches */
3693 if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3694 /* Now see if it matches */
3695 if (s->nb_streams == feed->nb_streams) {
3697 for(i=0;i<s->nb_streams;i++) {
3699 sf = feed->streams[i];
3702 if (sf->index != ss->index ||
3704 http_log("Index & Id do not match for stream %d (%s)\n",
3705 i, feed->feed_filename);
3708 AVCodecContext *ccf, *ccs;
3712 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3714 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3715 http_log("Codecs do not match for stream %d\n", i);
3717 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3718 http_log("Codec bitrates do not match for stream %d\n", i);
3720 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3721 if (CHECK_CODEC(time_base.den) ||
3722 CHECK_CODEC(time_base.num) ||
3723 CHECK_CODEC(width) ||
3724 CHECK_CODEC(height)) {
3725 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3728 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3729 if (CHECK_CODEC(sample_rate) ||
3730 CHECK_CODEC(channels) ||
3731 CHECK_CODEC(frame_size)) {
3732 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3736 http_log("Unknown codec type\n");
3744 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3745 feed->feed_filename, s->nb_streams, feed->nb_streams);
3747 av_close_input_file(s);
3749 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3750 feed->feed_filename);
3753 if (feed->readonly) {
3754 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3755 feed->feed_filename);
3758 unlink(feed->feed_filename);
3761 if (!url_exist(feed->feed_filename)) {
3762 AVFormatContext s1 = {0}, *s = &s1;
3764 if (feed->readonly) {
3765 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3766 feed->feed_filename);
3770 /* only write the header of the ffm file */
3771 if (avio_open(&s->pb, feed->feed_filename, AVIO_WRONLY) < 0) {
3772 http_log("Could not open output feed file '%s'\n",
3773 feed->feed_filename);
3776 s->oformat = feed->fmt;
3777 s->nb_streams = feed->nb_streams;
3778 for(i=0;i<s->nb_streams;i++) {
3780 st = feed->streams[i];
3783 av_set_parameters(s, NULL);
3784 if (av_write_header(s) < 0) {
3785 http_log("Container doesn't supports the required parameters\n");
3788 /* XXX: need better api */
3789 av_freep(&s->priv_data);
3792 /* get feed size and write index */
3793 fd = open(feed->feed_filename, O_RDONLY);
3795 http_log("Could not open output feed file '%s'\n",
3796 feed->feed_filename);
3800 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3801 feed->feed_size = lseek(fd, 0, SEEK_END);
3802 /* ensure that we do not wrap before the end of file */
3803 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3804 feed->feed_max_size = feed->feed_size;
3810 /* compute the bandwidth used by each stream */
3811 static void compute_bandwidth(void)
3817 for(stream = first_stream; stream != NULL; stream = stream->next) {
3819 for(i=0;i<stream->nb_streams;i++) {
3820 AVStream *st = stream->streams[i];
3821 switch(st->codec->codec_type) {
3822 case AVMEDIA_TYPE_AUDIO:
3823 case AVMEDIA_TYPE_VIDEO:
3824 bandwidth += st->codec->bit_rate;
3830 stream->bandwidth = (bandwidth + 999) / 1000;
3834 /* add a codec and set the default parameters */
3835 static void add_codec(FFStream *stream, AVCodecContext *av)
3839 /* compute default parameters */
3840 switch(av->codec_type) {
3841 case AVMEDIA_TYPE_AUDIO:
3842 if (av->bit_rate == 0)
3843 av->bit_rate = 64000;
3844 if (av->sample_rate == 0)
3845 av->sample_rate = 22050;
3846 if (av->channels == 0)
3849 case AVMEDIA_TYPE_VIDEO:
3850 if (av->bit_rate == 0)
3851 av->bit_rate = 64000;
3852 if (av->time_base.num == 0){
3853 av->time_base.den = 5;
3854 av->time_base.num = 1;
3856 if (av->width == 0 || av->height == 0) {
3860 /* Bitrate tolerance is less for streaming */
3861 if (av->bit_rate_tolerance == 0)
3862 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3863 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3868 if (av->max_qdiff == 0)
3870 av->qcompress = 0.5;
3873 if (!av->nsse_weight)
3874 av->nsse_weight = 8;
3876 av->frame_skip_cmp = FF_CMP_DCTMAX;
3878 av->me_method = ME_EPZS;
3879 av->rc_buffer_aggressivity = 1.0;
3882 av->rc_eq = "tex^qComp";
3883 if (!av->i_quant_factor)
3884 av->i_quant_factor = -0.8;
3885 if (!av->b_quant_factor)
3886 av->b_quant_factor = 1.25;
3887 if (!av->b_quant_offset)
3888 av->b_quant_offset = 1.25;
3889 if (!av->rc_max_rate)
3890 av->rc_max_rate = av->bit_rate * 2;
3892 if (av->rc_max_rate && !av->rc_buffer_size) {
3893 av->rc_buffer_size = av->rc_max_rate;
3902 st = av_mallocz(sizeof(AVStream));
3905 st->codec = avcodec_alloc_context();
3906 stream->streams[stream->nb_streams++] = st;
3907 memcpy(st->codec, av, sizeof(AVCodecContext));
3910 static enum CodecID opt_audio_codec(const char *arg)
3912 AVCodec *p= avcodec_find_encoder_by_name(arg);
3914 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3915 return CODEC_ID_NONE;
3920 static enum CodecID opt_video_codec(const char *arg)
3922 AVCodec *p= avcodec_find_encoder_by_name(arg);
3924 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3925 return CODEC_ID_NONE;
3930 /* simplistic plugin support */
3933 static void load_module(const char *filename)
3936 void (*init_func)(void);
3937 dll = dlopen(filename, RTLD_NOW);
3939 fprintf(stderr, "Could not load module '%s' - %s\n",
3940 filename, dlerror());
3944 init_func = dlsym(dll, "ffserver_module_init");
3947 "%s: init function 'ffserver_module_init()' not found\n",
3956 static int ffserver_opt_default(const char *opt, const char *arg,
3957 AVCodecContext *avctx, int type)
3960 const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3962 ret = av_set_string3(avctx, opt, arg, 1, NULL);
3966 static int ffserver_opt_preset(const char *arg,
3967 AVCodecContext *avctx, int type,
3968 enum CodecID *audio_id, enum CodecID *video_id)
3971 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3973 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3975 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3976 codec ? codec->name : NULL))) {
3977 fprintf(stderr, "File for preset '%s' not found\n", arg);
3982 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3983 if(line[0] == '#' && !e)
3985 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3987 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3991 if(!strcmp(tmp, "acodec")){
3992 *audio_id = opt_audio_codec(tmp2);
3993 }else if(!strcmp(tmp, "vcodec")){
3994 *video_id = opt_video_codec(tmp2);
3995 }else if(!strcmp(tmp, "scodec")){
3996 /* opt_subtitle_codec(tmp2); */
3997 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3998 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4009 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4010 const char *mime_type)
4012 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4015 AVOutputFormat *stream_fmt;
4016 char stream_format_name[64];
4018 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4019 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4028 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4032 fprintf(stderr, "%s:%d: ", filename, line_num);
4033 vfprintf(stderr, fmt, vl);
4039 static int parse_ffconfig(const char *filename)
4046 int val, errors, line_num;
4047 FFStream **last_stream, *stream, *redirect;
4048 FFStream **last_feed, *feed, *s;
4049 AVCodecContext audio_enc, video_enc;
4050 enum CodecID audio_id, video_id;
4052 f = fopen(filename, "r");
4060 first_stream = NULL;
4061 last_stream = &first_stream;
4063 last_feed = &first_feed;
4067 audio_id = CODEC_ID_NONE;
4068 video_id = CODEC_ID_NONE;
4070 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4072 if (fgets(line, sizeof(line), f) == NULL)
4078 if (*p == '\0' || *p == '#')
4081 get_arg(cmd, sizeof(cmd), &p);
4083 if (!strcasecmp(cmd, "Port")) {
4084 get_arg(arg, sizeof(arg), &p);
4086 if (val < 1 || val > 65536) {
4087 ERROR("Invalid_port: %s\n", arg);
4089 my_http_addr.sin_port = htons(val);
4090 } else if (!strcasecmp(cmd, "BindAddress")) {
4091 get_arg(arg, sizeof(arg), &p);
4092 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4093 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4095 } else if (!strcasecmp(cmd, "NoDaemon")) {
4096 ffserver_daemon = 0;
4097 } else if (!strcasecmp(cmd, "RTSPPort")) {
4098 get_arg(arg, sizeof(arg), &p);
4100 if (val < 1 || val > 65536) {
4101 ERROR("%s:%d: Invalid port: %s\n", arg);
4103 my_rtsp_addr.sin_port = htons(atoi(arg));
4104 } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4105 get_arg(arg, sizeof(arg), &p);
4106 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4107 ERROR("Invalid host/IP address: %s\n", arg);
4109 } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4110 get_arg(arg, sizeof(arg), &p);
4112 if (val < 1 || val > 65536) {
4113 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4115 nb_max_http_connections = val;
4116 } else if (!strcasecmp(cmd, "MaxClients")) {
4117 get_arg(arg, sizeof(arg), &p);
4119 if (val < 1 || val > nb_max_http_connections) {
4120 ERROR("Invalid MaxClients: %s\n", arg);
4122 nb_max_connections = val;
4124 } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4126 get_arg(arg, sizeof(arg), &p);
4128 if (llval < 10 || llval > 10000000) {
4129 ERROR("Invalid MaxBandwidth: %s\n", arg);
4131 max_bandwidth = llval;
4132 } else if (!strcasecmp(cmd, "CustomLog")) {
4133 if (!ffserver_debug)
4134 get_arg(logfilename, sizeof(logfilename), &p);
4135 } else if (!strcasecmp(cmd, "<Feed")) {
4136 /*********************************************/
4137 /* Feed related options */
4139 if (stream || feed) {
4140 ERROR("Already in a tag\n");
4142 feed = av_mallocz(sizeof(FFStream));
4143 get_arg(feed->filename, sizeof(feed->filename), &p);
4144 q = strrchr(feed->filename, '>');
4148 for (s = first_feed; s; s = s->next) {
4149 if (!strcmp(feed->filename, s->filename)) {
4150 ERROR("Feed '%s' already registered\n", s->filename);
4154 feed->fmt = av_guess_format("ffm", NULL, NULL);
4155 /* defaut feed file */
4156 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4157 "/tmp/%s.ffm", feed->filename);
4158 feed->feed_max_size = 5 * 1024 * 1024;
4160 feed->feed = feed; /* self feeding :-) */
4162 /* add in stream list */
4163 *last_stream = feed;
4164 last_stream = &feed->next;
4165 /* add in feed list */
4167 last_feed = &feed->next_feed;
4169 } else if (!strcasecmp(cmd, "Launch")) {
4173 feed->child_argv = av_mallocz(64 * sizeof(char *));
4175 for (i = 0; i < 62; i++) {
4176 get_arg(arg, sizeof(arg), &p);
4180 feed->child_argv[i] = av_strdup(arg);
4183 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4185 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4187 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4188 inet_ntoa(my_http_addr.sin_addr),
4189 ntohs(my_http_addr.sin_port), feed->filename);
4191 } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4193 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4195 } else if (stream) {
4196 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4198 } else if (!strcasecmp(cmd, "File")) {
4200 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4202 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4203 } else if (!strcasecmp(cmd, "Truncate")) {
4205 get_arg(arg, sizeof(arg), &p);
4206 feed->truncate = strtod(arg, NULL);
4208 } else if (!strcasecmp(cmd, "FileMaxSize")) {
4213 get_arg(arg, sizeof(arg), &p);
4215 fsize = strtod(p1, &p1);
4216 switch(toupper(*p1)) {
4221 fsize *= 1024 * 1024;
4224 fsize *= 1024 * 1024 * 1024;
4227 feed->feed_max_size = (int64_t)fsize;
4228 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4229 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4232 } else if (!strcasecmp(cmd, "</Feed>")) {
4234 ERROR("No corresponding <Feed> for </Feed>\n");
4237 } else if (!strcasecmp(cmd, "<Stream")) {
4238 /*********************************************/
4239 /* Stream related options */
4241 if (stream || feed) {
4242 ERROR("Already in a tag\n");
4245 stream = av_mallocz(sizeof(FFStream));
4246 get_arg(stream->filename, sizeof(stream->filename), &p);
4247 q = strrchr(stream->filename, '>');
4251 for (s = first_stream; s; s = s->next) {
4252 if (!strcmp(stream->filename, s->filename)) {
4253 ERROR("Stream '%s' already registered\n", s->filename);
4257 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4258 avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4259 avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4260 audio_id = CODEC_ID_NONE;
4261 video_id = CODEC_ID_NONE;
4263 audio_id = stream->fmt->audio_codec;
4264 video_id = stream->fmt->video_codec;
4267 *last_stream = stream;
4268 last_stream = &stream->next;
4270 } else if (!strcasecmp(cmd, "Feed")) {
4271 get_arg(arg, sizeof(arg), &p);
4276 while (sfeed != NULL) {
4277 if (!strcmp(sfeed->filename, arg))
4279 sfeed = sfeed->next_feed;
4282 ERROR("feed '%s' not defined\n", arg);
4284 stream->feed = sfeed;
4286 } else if (!strcasecmp(cmd, "Format")) {
4287 get_arg(arg, sizeof(arg), &p);
4289 if (!strcmp(arg, "status")) {
4290 stream->stream_type = STREAM_TYPE_STATUS;
4293 stream->stream_type = STREAM_TYPE_LIVE;
4294 /* jpeg cannot be used here, so use single frame jpeg */
4295 if (!strcmp(arg, "jpeg"))
4296 strcpy(arg, "mjpeg");
4297 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4299 ERROR("Unknown Format: %s\n", arg);
4303 audio_id = stream->fmt->audio_codec;
4304 video_id = stream->fmt->video_codec;
4307 } else if (!strcasecmp(cmd, "InputFormat")) {
4308 get_arg(arg, sizeof(arg), &p);
4310 stream->ifmt = av_find_input_format(arg);
4311 if (!stream->ifmt) {
4312 ERROR("Unknown input format: %s\n", arg);
4315 } else if (!strcasecmp(cmd, "FaviconURL")) {
4316 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4317 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4319 ERROR("FaviconURL only permitted for status streams\n");
4321 } else if (!strcasecmp(cmd, "Author")) {
4323 get_arg(stream->author, sizeof(stream->author), &p);
4324 } else if (!strcasecmp(cmd, "Comment")) {
4326 get_arg(stream->comment, sizeof(stream->comment), &p);
4327 } else if (!strcasecmp(cmd, "Copyright")) {
4329 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4330 } else if (!strcasecmp(cmd, "Title")) {
4332 get_arg(stream->title, sizeof(stream->title), &p);
4333 } else if (!strcasecmp(cmd, "Preroll")) {
4334 get_arg(arg, sizeof(arg), &p);
4336 stream->prebuffer = atof(arg) * 1000;
4337 } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4339 stream->send_on_key = 1;
4340 } else if (!strcasecmp(cmd, "AudioCodec")) {
4341 get_arg(arg, sizeof(arg), &p);
4342 audio_id = opt_audio_codec(arg);
4343 if (audio_id == CODEC_ID_NONE) {
4344 ERROR("Unknown AudioCodec: %s\n", arg);
4346 } else if (!strcasecmp(cmd, "VideoCodec")) {
4347 get_arg(arg, sizeof(arg), &p);
4348 video_id = opt_video_codec(arg);
4349 if (video_id == CODEC_ID_NONE) {
4350 ERROR("Unknown VideoCodec: %s\n", arg);
4352 } else if (!strcasecmp(cmd, "MaxTime")) {
4353 get_arg(arg, sizeof(arg), &p);
4355 stream->max_time = atof(arg) * 1000;
4356 } else if (!strcasecmp(cmd, "AudioBitRate")) {
4357 get_arg(arg, sizeof(arg), &p);
4359 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4360 } else if (!strcasecmp(cmd, "AudioChannels")) {
4361 get_arg(arg, sizeof(arg), &p);
4363 audio_enc.channels = atoi(arg);
4364 } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4365 get_arg(arg, sizeof(arg), &p);
4367 audio_enc.sample_rate = atoi(arg);
4368 } else if (!strcasecmp(cmd, "AudioQuality")) {
4369 get_arg(arg, sizeof(arg), &p);
4371 // audio_enc.quality = atof(arg) * 1000;
4373 } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4375 int minrate, maxrate;
4377 get_arg(arg, sizeof(arg), &p);
4379 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4380 video_enc.rc_min_rate = minrate * 1000;
4381 video_enc.rc_max_rate = maxrate * 1000;
4383 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4386 } else if (!strcasecmp(cmd, "Debug")) {
4388 get_arg(arg, sizeof(arg), &p);
4389 video_enc.debug = strtol(arg,0,0);
4391 } else if (!strcasecmp(cmd, "Strict")) {
4393 get_arg(arg, sizeof(arg), &p);
4394 video_enc.strict_std_compliance = atoi(arg);
4396 } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4398 get_arg(arg, sizeof(arg), &p);
4399 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4401 } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4403 get_arg(arg, sizeof(arg), &p);
4404 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4406 } else if (!strcasecmp(cmd, "VideoBitRate")) {
4407 get_arg(arg, sizeof(arg), &p);
4409 video_enc.bit_rate = atoi(arg) * 1000;
4411 } else if (!strcasecmp(cmd, "VideoSize")) {
4412 get_arg(arg, sizeof(arg), &p);
4414 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4415 if ((video_enc.width % 16) != 0 ||
4416 (video_enc.height % 16) != 0) {
4417 ERROR("Image size must be a multiple of 16\n");
4420 } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4421 get_arg(arg, sizeof(arg), &p);
4423 AVRational frame_rate;
4424 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4425 ERROR("Incorrect frame rate: %s\n", arg);
4427 video_enc.time_base.num = frame_rate.den;
4428 video_enc.time_base.den = frame_rate.num;
4431 } else if (!strcasecmp(cmd, "VideoGopSize")) {
4432 get_arg(arg, sizeof(arg), &p);
4434 video_enc.gop_size = atoi(arg);
4435 } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4437 video_enc.gop_size = 1;
4438 } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4440 video_enc.mb_decision = FF_MB_DECISION_BITS;
4441 } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4443 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4444 video_enc.flags |= CODEC_FLAG_4MV;
4446 } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4447 !strcasecmp(cmd, "AVOptionAudio")) {
4449 AVCodecContext *avctx;
4451 get_arg(arg, sizeof(arg), &p);
4452 get_arg(arg2, sizeof(arg2), &p);
4453 if (!strcasecmp(cmd, "AVOptionVideo")) {
4455 type = AV_OPT_FLAG_VIDEO_PARAM;
4458 type = AV_OPT_FLAG_AUDIO_PARAM;
4460 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4461 ERROR("AVOption error: %s %s\n", arg, arg2);
4463 } else if (!strcasecmp(cmd, "AVPresetVideo") ||
4464 !strcasecmp(cmd, "AVPresetAudio")) {
4465 AVCodecContext *avctx;
4467 get_arg(arg, sizeof(arg), &p);
4468 if (!strcasecmp(cmd, "AVPresetVideo")) {
4470 video_enc.codec_id = video_id;
4471 type = AV_OPT_FLAG_VIDEO_PARAM;
4474 audio_enc.codec_id = audio_id;
4475 type = AV_OPT_FLAG_AUDIO_PARAM;
4477 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4478 ERROR("AVPreset error: %s\n", arg);
4480 } else if (!strcasecmp(cmd, "VideoTag")) {
4481 get_arg(arg, sizeof(arg), &p);
4482 if ((strlen(arg) == 4) && stream)
4483 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4484 } else if (!strcasecmp(cmd, "BitExact")) {
4486 video_enc.flags |= CODEC_FLAG_BITEXACT;
4487 } else if (!strcasecmp(cmd, "DctFastint")) {
4489 video_enc.dct_algo = FF_DCT_FASTINT;
4490 } else if (!strcasecmp(cmd, "IdctSimple")) {
4492 video_enc.idct_algo = FF_IDCT_SIMPLE;
4493 } else if (!strcasecmp(cmd, "Qscale")) {
4494 get_arg(arg, sizeof(arg), &p);
4496 video_enc.flags |= CODEC_FLAG_QSCALE;
4497 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4499 } else if (!strcasecmp(cmd, "VideoQDiff")) {
4500 get_arg(arg, sizeof(arg), &p);
4502 video_enc.max_qdiff = atoi(arg);
4503 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4504 ERROR("VideoQDiff out of range\n");
4507 } else if (!strcasecmp(cmd, "VideoQMax")) {
4508 get_arg(arg, sizeof(arg), &p);
4510 video_enc.qmax = atoi(arg);
4511 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4512 ERROR("VideoQMax out of range\n");
4515 } else if (!strcasecmp(cmd, "VideoQMin")) {
4516 get_arg(arg, sizeof(arg), &p);
4518 video_enc.qmin = atoi(arg);
4519 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4520 ERROR("VideoQMin out of range\n");
4523 } else if (!strcasecmp(cmd, "LumaElim")) {
4524 get_arg(arg, sizeof(arg), &p);
4526 video_enc.luma_elim_threshold = atoi(arg);
4527 } else if (!strcasecmp(cmd, "ChromaElim")) {
4528 get_arg(arg, sizeof(arg), &p);
4530 video_enc.chroma_elim_threshold = atoi(arg);
4531 } else if (!strcasecmp(cmd, "LumiMask")) {
4532 get_arg(arg, sizeof(arg), &p);
4534 video_enc.lumi_masking = atof(arg);
4535 } else if (!strcasecmp(cmd, "DarkMask")) {
4536 get_arg(arg, sizeof(arg), &p);
4538 video_enc.dark_masking = atof(arg);
4539 } else if (!strcasecmp(cmd, "NoVideo")) {
4540 video_id = CODEC_ID_NONE;
4541 } else if (!strcasecmp(cmd, "NoAudio")) {
4542 audio_id = CODEC_ID_NONE;
4543 } else if (!strcasecmp(cmd, "ACL")) {
4544 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4545 } else if (!strcasecmp(cmd, "DynamicACL")) {
4547 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4549 } else if (!strcasecmp(cmd, "RTSPOption")) {
4550 get_arg(arg, sizeof(arg), &p);
4552 av_freep(&stream->rtsp_option);
4553 stream->rtsp_option = av_strdup(arg);
4555 } else if (!strcasecmp(cmd, "MulticastAddress")) {
4556 get_arg(arg, sizeof(arg), &p);
4558 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4559 ERROR("Invalid host/IP address: %s\n", arg);
4561 stream->is_multicast = 1;
4562 stream->loop = 1; /* default is looping */
4564 } else if (!strcasecmp(cmd, "MulticastPort")) {
4565 get_arg(arg, sizeof(arg), &p);
4567 stream->multicast_port = atoi(arg);
4568 } else if (!strcasecmp(cmd, "MulticastTTL")) {
4569 get_arg(arg, sizeof(arg), &p);
4571 stream->multicast_ttl = atoi(arg);
4572 } else if (!strcasecmp(cmd, "NoLoop")) {
4575 } else if (!strcasecmp(cmd, "</Stream>")) {
4577 ERROR("No corresponding <Stream> for </Stream>\n");
4579 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4580 if (audio_id != CODEC_ID_NONE) {
4581 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4582 audio_enc.codec_id = audio_id;
4583 add_codec(stream, &audio_enc);
4585 if (video_id != CODEC_ID_NONE) {
4586 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4587 video_enc.codec_id = video_id;
4588 add_codec(stream, &video_enc);
4593 } else if (!strcasecmp(cmd, "<Redirect")) {
4594 /*********************************************/
4596 if (stream || feed || redirect) {
4597 ERROR("Already in a tag\n");
4599 redirect = av_mallocz(sizeof(FFStream));
4600 *last_stream = redirect;
4601 last_stream = &redirect->next;
4603 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4604 q = strrchr(redirect->filename, '>');
4607 redirect->stream_type = STREAM_TYPE_REDIRECT;
4609 } else if (!strcasecmp(cmd, "URL")) {
4611 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4612 } else if (!strcasecmp(cmd, "</Redirect>")) {
4614 ERROR("No corresponding <Redirect> for </Redirect>\n");
4616 if (!redirect->feed_filename[0]) {
4617 ERROR("No URL found for <Redirect>\n");
4621 } else if (!strcasecmp(cmd, "LoadModule")) {
4622 get_arg(arg, sizeof(arg), &p);
4626 ERROR("Module support not compiled into this version: '%s'\n", arg);
4629 ERROR("Incorrect keyword: '%s'\n", cmd);
4641 static void handle_child_exit(int sig)
4646 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4649 for (feed = first_feed; feed; feed = feed->next) {
4650 if (feed->pid == pid) {
4651 int uptime = time(0) - feed->pid_start;
4654 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4657 /* Turn off any more restarts */
4658 feed->child_argv = 0;
4663 need_to_start_children = 1;
4666 static void opt_debug(void)
4669 ffserver_daemon = 0;
4670 logfilename[0] = '-';
4673 static void show_help(void)
4675 printf("usage: ffserver [options]\n"
4676 "Hyper fast multi format Audio/Video streaming server\n");
4678 show_help_options(options, "Main options:\n", 0, 0);
4681 static const OptionDef options[] = {
4682 #include "cmdutils_common_opts.h"
4683 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4684 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4685 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4689 int main(int argc, char **argv)
4691 struct sigaction sigact;
4697 my_program_name = argv[0];
4698 my_program_dir = getcwd(0, 0);
4699 ffserver_daemon = 1;
4701 parse_options(argc, argv, options, NULL);
4703 unsetenv("http_proxy"); /* Kill the http_proxy */
4705 av_lfg_init(&random_state, av_get_random_seed());
4707 memset(&sigact, 0, sizeof(sigact));
4708 sigact.sa_handler = handle_child_exit;
4709 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4710 sigaction(SIGCHLD, &sigact, 0);
4712 if (parse_ffconfig(config_filename) < 0) {
4713 fprintf(stderr, "Incorrect config file - exiting.\n");
4717 /* open log file if needed */
4718 if (logfilename[0] != '\0') {
4719 if (!strcmp(logfilename, "-"))
4722 logfile = fopen(logfilename, "a");
4723 av_log_set_callback(http_av_log);
4726 build_file_streams();
4728 build_feed_streams();
4730 compute_bandwidth();
4732 /* put the process in background and detach it from its TTY */
4733 if (ffserver_daemon) {
4740 } else if (pid > 0) {
4747 open("/dev/null", O_RDWR);
4748 if (strcmp(logfilename, "-") != 0) {
4758 signal(SIGPIPE, SIG_IGN);
4760 if (ffserver_daemon)
4763 if (http_server() < 0) {
4764 http_log("Could not start server\n");