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
24 #define closesocket close
29 #include "libavformat/avformat.h"
30 #include "libavformat/ffm.h"
31 #include "libavformat/network.h"
32 #include "libavformat/os_support.h"
33 #include "libavformat/rtpdec.h"
34 #include "libavformat/rtsp.h"
35 // XXX for ffio_open_dyn_packet_buffer, to be removed
36 #include "libavformat/avio_internal.h"
37 #include "libavutil/avstring.h"
38 #include "libavutil/lfg.h"
39 #include "libavutil/random_seed.h"
40 #include "libavutil/parseutils.h"
41 #include "libavutil/opt.h"
45 #include <sys/ioctl.h>
60 const char program_name[] = "ffserver";
61 const int program_birth_year = 2000;
63 static const OptionDef options[];
66 HTTPSTATE_WAIT_REQUEST,
67 HTTPSTATE_SEND_HEADER,
68 HTTPSTATE_SEND_DATA_HEADER,
69 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
70 HTTPSTATE_SEND_DATA_TRAILER,
71 HTTPSTATE_RECEIVE_DATA,
72 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
75 RTSPSTATE_WAIT_REQUEST,
77 RTSPSTATE_SEND_PACKET,
80 static const char *http_state[] = {
96 #define MAX_STREAMS 20
98 #define IOBUFFER_INIT_SIZE 8192
100 /* timeouts are in ms */
101 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
102 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
104 #define SYNC_TIMEOUT (10 * 1000)
106 typedef struct RTSPActionServerSetup {
108 char transport_option[512];
109 } RTSPActionServerSetup;
112 int64_t count1, count2;
113 int64_t time1, time2;
116 /* context associated with one connection */
117 typedef struct HTTPContext {
118 enum HTTPState state;
119 int fd; /* socket file descriptor */
120 struct sockaddr_in from_addr; /* origin */
121 struct pollfd *poll_entry; /* used when polling */
123 uint8_t *buffer_ptr, *buffer_end;
126 int chunked_encoding;
127 int chunk_size; /* 0 if it needs to be read */
128 struct HTTPContext *next;
129 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
133 /* input format handling */
134 AVFormatContext *fmt_in;
135 int64_t start_time; /* In milliseconds - this wraps fairly often */
136 int64_t first_pts; /* initial pts value */
137 int64_t cur_pts; /* current pts value from the stream in us */
138 int64_t cur_frame_duration; /* duration of the current frame in us */
139 int cur_frame_bytes; /* output frame size, needed to compute
140 the time at which we send each
142 int pts_stream_index; /* stream we choose as clock reference */
143 int64_t cur_clock; /* current clock reference value in us */
144 /* output format handling */
145 struct FFStream *stream;
146 /* -1 is invalid stream */
147 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
148 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
150 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
151 int last_packet_sent; /* true if last data packet was sent */
153 DataRateData datarate;
160 int is_packetized; /* if true, the stream is packetized */
161 int packet_stream_index; /* current stream for output in state machine */
163 /* RTSP state specific */
164 uint8_t *pb_buffer; /* XXX: use that in all the code */
166 int seq; /* RTSP sequence number */
168 /* RTP state specific */
169 enum RTSPLowerTransport rtp_protocol;
170 char session_id[32]; /* session id */
171 AVFormatContext *rtp_ctx[MAX_STREAMS];
173 /* RTP/UDP specific */
174 URLContext *rtp_handles[MAX_STREAMS];
176 /* RTP/TCP specific */
177 struct HTTPContext *rtsp_c;
178 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
181 /* each generated stream is described here */
185 STREAM_TYPE_REDIRECT,
188 enum IPAddressAction {
193 typedef struct IPAddressACL {
194 struct IPAddressACL *next;
195 enum IPAddressAction action;
196 /* These are in host order */
197 struct in_addr first;
201 /* description of each stream of the ffserver.conf file */
202 typedef struct FFStream {
203 enum StreamType stream_type;
204 char filename[1024]; /* stream filename */
205 struct FFStream *feed; /* feed we are using (can be null if
207 AVFormatParameters *ap_in; /* input parameters */
208 AVInputFormat *ifmt; /* if non NULL, force input format */
211 char dynamic_acl[1024];
213 int prebuffer; /* Number of millseconds early to start */
214 int64_t max_time; /* Number of milliseconds to run */
216 AVStream *streams[MAX_STREAMS];
217 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
218 char feed_filename[1024]; /* file name of the feed storage, or
219 input file name for a stream */
224 pid_t pid; /* Of ffmpeg process */
225 time_t pid_start; /* Of ffmpeg process */
227 struct FFStream *next;
228 unsigned bandwidth; /* bandwidth, in kbits/s */
231 /* multicast specific */
233 struct in_addr multicast_ip;
234 int multicast_port; /* first port used for multicast */
236 int loop; /* if true, send the stream in loops (only meaningful if file) */
239 int feed_opened; /* true if someone is writing to the feed */
240 int is_feed; /* true if it is a feed */
241 int readonly; /* True if writing is prohibited to the file */
242 int truncate; /* True if feeder connection truncate the feed file */
244 int64_t bytes_served;
245 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
246 int64_t feed_write_index; /* current write position in feed (it wraps around) */
247 int64_t feed_size; /* current size of feed */
248 struct FFStream *next_feed;
251 typedef struct FeedData {
252 long long data_count;
253 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
256 static struct sockaddr_in my_http_addr;
257 static struct sockaddr_in my_rtsp_addr;
259 static char logfilename[1024];
260 static HTTPContext *first_http_ctx;
261 static FFStream *first_feed; /* contains only feeds */
262 static FFStream *first_stream; /* contains all streams, including feeds */
264 static void new_connection(int server_fd, int is_rtsp);
265 static void close_connection(HTTPContext *c);
268 static int handle_connection(HTTPContext *c);
269 static int http_parse_request(HTTPContext *c);
270 static int http_send_data(HTTPContext *c);
271 static void compute_status(HTTPContext *c);
272 static int open_input_stream(HTTPContext *c, const char *info);
273 static int http_start_receive_data(HTTPContext *c);
274 static int http_receive_data(HTTPContext *c);
277 static int rtsp_parse_request(HTTPContext *c);
278 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
279 static void rtsp_cmd_options(HTTPContext *c, const char *url);
280 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
281 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
282 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
283 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
286 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
287 struct in_addr my_ip);
290 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
291 FFStream *stream, const char *session_id,
292 enum RTSPLowerTransport rtp_protocol);
293 static int rtp_new_av_stream(HTTPContext *c,
294 int stream_index, struct sockaddr_in *dest_addr,
295 HTTPContext *rtsp_c);
297 static const char *my_program_name;
298 static const char *my_program_dir;
300 static const char *config_filename = "/etc/ffserver.conf";
302 static int ffserver_debug;
303 static int ffserver_daemon;
304 static int no_launch;
305 static int need_to_start_children;
307 /* maximum number of simultaneous HTTP connections */
308 static unsigned int nb_max_http_connections = 2000;
309 static unsigned int nb_max_connections = 5;
310 static unsigned int nb_connections;
312 static uint64_t max_bandwidth = 1000;
313 static uint64_t current_bandwidth;
315 static int64_t cur_time; // Making this global saves on passing it around everywhere
317 static AVLFG random_state;
319 static FILE *logfile = NULL;
321 /* FIXME: make ffserver work with IPv6 */
322 /* resolve host with also IP address parsing */
323 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
326 if (!ff_inet_aton(hostname, sin_addr)) {
328 struct addrinfo *ai, *cur;
329 struct addrinfo hints;
330 memset(&hints, 0, sizeof(hints));
331 hints.ai_family = AF_INET;
332 if (getaddrinfo(hostname, NULL, &hints, &ai))
334 /* getaddrinfo returns a linked list of addrinfo structs.
335 * Even if we set ai_family = AF_INET above, make sure
336 * that the returned one actually is of the correct type. */
337 for (cur = ai; cur; cur = cur->ai_next) {
338 if (cur->ai_family == AF_INET) {
339 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
348 hp = gethostbyname(hostname);
351 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
357 static char *ctime1(char *buf2)
365 p = buf2 + strlen(p) - 1;
371 static void http_vlog(const char *fmt, va_list vargs)
373 static int print_prefix = 1;
378 fprintf(logfile, "%s ", buf);
380 print_prefix = strstr(fmt, "\n") != NULL;
381 vfprintf(logfile, fmt, vargs);
387 __attribute__ ((format (printf, 1, 2)))
389 static void http_log(const char *fmt, ...)
392 va_start(vargs, fmt);
393 http_vlog(fmt, vargs);
397 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
399 static int print_prefix = 1;
400 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
401 if (level > av_log_get_level())
403 if (print_prefix && avc)
404 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
405 print_prefix = strstr(fmt, "\n") != NULL;
406 http_vlog(fmt, vargs);
409 static void log_connection(HTTPContext *c)
414 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
415 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
416 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
419 static void update_datarate(DataRateData *drd, int64_t count)
421 if (!drd->time1 && !drd->count1) {
422 drd->time1 = drd->time2 = cur_time;
423 drd->count1 = drd->count2 = count;
424 } else if (cur_time - drd->time2 > 5000) {
425 drd->time1 = drd->time2;
426 drd->count1 = drd->count2;
427 drd->time2 = cur_time;
432 /* In bytes per second */
433 static int compute_datarate(DataRateData *drd, int64_t count)
435 if (cur_time == drd->time1)
438 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
442 static void start_children(FFStream *feed)
447 for (; feed; feed = feed->next) {
448 if (feed->child_argv && !feed->pid) {
449 feed->pid_start = time(0);
454 http_log("Unable to create children\n");
463 av_strlcpy(pathname, my_program_name, sizeof(pathname));
465 slash = strrchr(pathname, '/');
470 strcpy(slash, "ffmpeg");
472 http_log("Launch commandline: ");
473 http_log("%s ", pathname);
474 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
475 http_log("%s ", feed->child_argv[i]);
478 for (i = 3; i < 256; i++)
481 if (!ffserver_debug) {
482 i = open("/dev/null", O_RDWR);
491 /* This is needed to make relative pathnames work */
492 chdir(my_program_dir);
494 signal(SIGPIPE, SIG_DFL);
496 execvp(pathname, feed->child_argv);
504 /* open a listening socket */
505 static int socket_open_listen(struct sockaddr_in *my_addr)
509 server_fd = socket(AF_INET,SOCK_STREAM,0);
516 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
518 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
520 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
522 closesocket(server_fd);
526 if (listen (server_fd, 5) < 0) {
528 closesocket(server_fd);
531 ff_socket_nonblock(server_fd, 1);
536 /* start all multicast streams */
537 static void start_multicast(void)
542 struct sockaddr_in dest_addr;
543 int default_port, stream_index;
546 for(stream = first_stream; stream != NULL; stream = stream->next) {
547 if (stream->is_multicast) {
548 /* open the RTP connection */
549 snprintf(session_id, sizeof(session_id), "%08x%08x",
550 av_lfg_get(&random_state), av_lfg_get(&random_state));
552 /* choose a port if none given */
553 if (stream->multicast_port == 0) {
554 stream->multicast_port = default_port;
558 dest_addr.sin_family = AF_INET;
559 dest_addr.sin_addr = stream->multicast_ip;
560 dest_addr.sin_port = htons(stream->multicast_port);
562 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
563 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
567 if (open_input_stream(rtp_c, "") < 0) {
568 http_log("Could not open input stream for stream '%s'\n",
573 /* open each RTP stream */
574 for(stream_index = 0; stream_index < stream->nb_streams;
576 dest_addr.sin_port = htons(stream->multicast_port +
578 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
579 http_log("Could not open output stream '%s/streamid=%d'\n",
580 stream->filename, stream_index);
585 /* change state to send data */
586 rtp_c->state = HTTPSTATE_SEND_DATA;
591 /* main loop of the http server */
592 static int http_server(void)
594 int server_fd = 0, rtsp_server_fd = 0;
595 int ret, delay, delay1;
596 struct pollfd *poll_table, *poll_entry;
597 HTTPContext *c, *c_next;
599 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
600 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
604 if (my_http_addr.sin_port) {
605 server_fd = socket_open_listen(&my_http_addr);
610 if (my_rtsp_addr.sin_port) {
611 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
612 if (rtsp_server_fd < 0)
616 if (!rtsp_server_fd && !server_fd) {
617 http_log("HTTP and RTSP disabled.\n");
621 http_log("FFserver started.\n");
623 start_children(first_feed);
628 poll_entry = poll_table;
630 poll_entry->fd = server_fd;
631 poll_entry->events = POLLIN;
634 if (rtsp_server_fd) {
635 poll_entry->fd = rtsp_server_fd;
636 poll_entry->events = POLLIN;
640 /* wait for events on each HTTP handle */
647 case HTTPSTATE_SEND_HEADER:
648 case RTSPSTATE_SEND_REPLY:
649 case RTSPSTATE_SEND_PACKET:
650 c->poll_entry = poll_entry;
652 poll_entry->events = POLLOUT;
655 case HTTPSTATE_SEND_DATA_HEADER:
656 case HTTPSTATE_SEND_DATA:
657 case HTTPSTATE_SEND_DATA_TRAILER:
658 if (!c->is_packetized) {
659 /* for TCP, we output as much as we can (may need to put a limit) */
660 c->poll_entry = poll_entry;
662 poll_entry->events = POLLOUT;
665 /* when ffserver is doing the timing, we work by
666 looking at which packet need to be sent every
668 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
673 case HTTPSTATE_WAIT_REQUEST:
674 case HTTPSTATE_RECEIVE_DATA:
675 case HTTPSTATE_WAIT_FEED:
676 case RTSPSTATE_WAIT_REQUEST:
677 /* need to catch errors */
678 c->poll_entry = poll_entry;
680 poll_entry->events = POLLIN;/* Maybe this will work */
684 c->poll_entry = NULL;
690 /* wait for an event on one connection. We poll at least every
691 second to handle timeouts */
693 ret = poll(poll_table, poll_entry - poll_table, delay);
694 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
695 ff_neterrno() != AVERROR(EINTR))
699 cur_time = av_gettime() / 1000;
701 if (need_to_start_children) {
702 need_to_start_children = 0;
703 start_children(first_feed);
706 /* now handle the events */
707 for(c = first_http_ctx; c != NULL; c = c_next) {
709 if (handle_connection(c) < 0) {
710 /* close and free the connection */
716 poll_entry = poll_table;
718 /* new HTTP connection request ? */
719 if (poll_entry->revents & POLLIN)
720 new_connection(server_fd, 0);
723 if (rtsp_server_fd) {
724 /* new RTSP connection request ? */
725 if (poll_entry->revents & POLLIN)
726 new_connection(rtsp_server_fd, 1);
731 /* start waiting for a new HTTP/RTSP request */
732 static void start_wait_request(HTTPContext *c, int is_rtsp)
734 c->buffer_ptr = c->buffer;
735 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
738 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
739 c->state = RTSPSTATE_WAIT_REQUEST;
741 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
742 c->state = HTTPSTATE_WAIT_REQUEST;
746 static void http_send_too_busy_reply(int fd)
749 int len = snprintf(buffer, sizeof(buffer),
750 "HTTP/1.0 503 Server too busy\r\n"
751 "Content-type: text/html\r\n"
753 "<html><head><title>Too busy</title></head><body>\r\n"
754 "<p>The server is too busy to serve your request at this time.</p>\r\n"
755 "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
756 "</body></html>\r\n",
757 nb_connections, nb_max_connections);
758 send(fd, buffer, len, 0);
762 static void new_connection(int server_fd, int is_rtsp)
764 struct sockaddr_in from_addr;
766 HTTPContext *c = NULL;
768 len = sizeof(from_addr);
769 fd = accept(server_fd, (struct sockaddr *)&from_addr,
772 http_log("error during accept %s\n", strerror(errno));
775 ff_socket_nonblock(fd, 1);
777 if (nb_connections >= nb_max_connections) {
778 http_send_too_busy_reply(fd);
782 /* add a new connection */
783 c = av_mallocz(sizeof(HTTPContext));
788 c->poll_entry = NULL;
789 c->from_addr = from_addr;
790 c->buffer_size = IOBUFFER_INIT_SIZE;
791 c->buffer = av_malloc(c->buffer_size);
795 c->next = first_http_ctx;
799 start_wait_request(c, is_rtsp);
811 static void close_connection(HTTPContext *c)
813 HTTPContext **cp, *c1;
815 AVFormatContext *ctx;
819 /* remove connection from list */
820 cp = &first_http_ctx;
821 while ((*cp) != NULL) {
829 /* remove references, if any (XXX: do it faster) */
830 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
835 /* remove connection associated resources */
839 /* close each frame parser */
840 for(i=0;i<c->fmt_in->nb_streams;i++) {
841 st = c->fmt_in->streams[i];
842 if (st->codec->codec)
843 avcodec_close(st->codec);
845 av_close_input_file(c->fmt_in);
848 /* free RTP output streams if any */
851 nb_streams = c->stream->nb_streams;
853 for(i=0;i<nb_streams;i++) {
856 av_write_trailer(ctx);
857 av_metadata_free(&ctx->metadata);
858 av_free(ctx->streams[0]);
861 h = c->rtp_handles[i];
868 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
871 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
872 av_write_trailer(ctx);
873 av_freep(&c->pb_buffer);
874 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
879 for(i=0; i<ctx->nb_streams; i++)
880 av_free(ctx->streams[i]);
882 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
883 current_bandwidth -= c->stream->bandwidth;
885 /* signal that there is no feed if we are the feeder socket */
886 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
887 c->stream->feed_opened = 0;
891 av_freep(&c->pb_buffer);
892 av_freep(&c->packet_buffer);
898 static int handle_connection(HTTPContext *c)
903 case HTTPSTATE_WAIT_REQUEST:
904 case RTSPSTATE_WAIT_REQUEST:
906 if ((c->timeout - cur_time) < 0)
908 if (c->poll_entry->revents & (POLLERR | POLLHUP))
911 /* no need to read if no events */
912 if (!(c->poll_entry->revents & POLLIN))
916 len = recv(c->fd, c->buffer_ptr, 1, 0);
918 if (ff_neterrno() != AVERROR(EAGAIN) &&
919 ff_neterrno() != AVERROR(EINTR))
921 } else if (len == 0) {
924 /* search for end of request. */
926 c->buffer_ptr += len;
928 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
929 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
930 /* request found : parse it and reply */
931 if (c->state == HTTPSTATE_WAIT_REQUEST) {
932 ret = http_parse_request(c);
934 ret = rtsp_parse_request(c);
938 } else if (ptr >= c->buffer_end) {
939 /* request too long: cannot do anything */
941 } else goto read_loop;
945 case HTTPSTATE_SEND_HEADER:
946 if (c->poll_entry->revents & (POLLERR | POLLHUP))
949 /* no need to write if no events */
950 if (!(c->poll_entry->revents & POLLOUT))
952 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
954 if (ff_neterrno() != AVERROR(EAGAIN) &&
955 ff_neterrno() != AVERROR(EINTR)) {
956 /* error : close connection */
957 av_freep(&c->pb_buffer);
961 c->buffer_ptr += len;
963 c->stream->bytes_served += len;
964 c->data_count += len;
965 if (c->buffer_ptr >= c->buffer_end) {
966 av_freep(&c->pb_buffer);
970 /* all the buffer was sent : synchronize to the incoming stream */
971 c->state = HTTPSTATE_SEND_DATA_HEADER;
972 c->buffer_ptr = c->buffer_end = c->buffer;
977 case HTTPSTATE_SEND_DATA:
978 case HTTPSTATE_SEND_DATA_HEADER:
979 case HTTPSTATE_SEND_DATA_TRAILER:
980 /* for packetized output, we consider we can always write (the
981 input streams sets the speed). It may be better to verify
982 that we do not rely too much on the kernel queues */
983 if (!c->is_packetized) {
984 if (c->poll_entry->revents & (POLLERR | POLLHUP))
987 /* no need to read if no events */
988 if (!(c->poll_entry->revents & POLLOUT))
991 if (http_send_data(c) < 0)
993 /* close connection if trailer sent */
994 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
997 case HTTPSTATE_RECEIVE_DATA:
998 /* no need to read if no events */
999 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1001 if (!(c->poll_entry->revents & POLLIN))
1003 if (http_receive_data(c) < 0)
1006 case HTTPSTATE_WAIT_FEED:
1007 /* no need to read if no events */
1008 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1011 /* nothing to do, we'll be waken up by incoming feed packets */
1014 case RTSPSTATE_SEND_REPLY:
1015 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1016 av_freep(&c->pb_buffer);
1019 /* no need to write if no events */
1020 if (!(c->poll_entry->revents & POLLOUT))
1022 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1024 if (ff_neterrno() != AVERROR(EAGAIN) &&
1025 ff_neterrno() != AVERROR(EINTR)) {
1026 /* error : close connection */
1027 av_freep(&c->pb_buffer);
1031 c->buffer_ptr += len;
1032 c->data_count += len;
1033 if (c->buffer_ptr >= c->buffer_end) {
1034 /* all the buffer was sent : wait for a new request */
1035 av_freep(&c->pb_buffer);
1036 start_wait_request(c, 1);
1040 case RTSPSTATE_SEND_PACKET:
1041 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1042 av_freep(&c->packet_buffer);
1045 /* no need to write if no events */
1046 if (!(c->poll_entry->revents & POLLOUT))
1048 len = send(c->fd, c->packet_buffer_ptr,
1049 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1051 if (ff_neterrno() != AVERROR(EAGAIN) &&
1052 ff_neterrno() != AVERROR(EINTR)) {
1053 /* error : close connection */
1054 av_freep(&c->packet_buffer);
1058 c->packet_buffer_ptr += len;
1059 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1060 /* all the buffer was sent : wait for a new request */
1061 av_freep(&c->packet_buffer);
1062 c->state = RTSPSTATE_WAIT_REQUEST;
1066 case HTTPSTATE_READY:
1075 static int extract_rates(char *rates, int ratelen, const char *request)
1079 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1080 if (strncasecmp(p, "Pragma:", 7) == 0) {
1081 const char *q = p + 7;
1083 while (*q && *q != '\n' && isspace(*q))
1086 if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1092 memset(rates, 0xff, ratelen);
1095 while (*q && *q != '\n' && *q != ':')
1098 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1102 if (stream_no < ratelen && stream_no >= 0)
1103 rates[stream_no] = rate_no;
1105 while (*q && *q != '\n' && !isspace(*q))
1112 p = strchr(p, '\n');
1122 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1125 int best_bitrate = 100000000;
1128 for (i = 0; i < feed->nb_streams; i++) {
1129 AVCodecContext *feed_codec = feed->streams[i]->codec;
1131 if (feed_codec->codec_id != codec->codec_id ||
1132 feed_codec->sample_rate != codec->sample_rate ||
1133 feed_codec->width != codec->width ||
1134 feed_codec->height != codec->height)
1137 /* Potential stream */
1139 /* We want the fastest stream less than bit_rate, or the slowest
1140 * faster than bit_rate
1143 if (feed_codec->bit_rate <= bit_rate) {
1144 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1145 best_bitrate = feed_codec->bit_rate;
1149 if (feed_codec->bit_rate < best_bitrate) {
1150 best_bitrate = feed_codec->bit_rate;
1159 static int modify_current_stream(HTTPContext *c, char *rates)
1162 FFStream *req = c->stream;
1163 int action_required = 0;
1165 /* Not much we can do for a feed */
1169 for (i = 0; i < req->nb_streams; i++) {
1170 AVCodecContext *codec = req->streams[i]->codec;
1174 c->switch_feed_streams[i] = req->feed_streams[i];
1177 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1180 /* Wants off or slow */
1181 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1183 /* This doesn't work well when it turns off the only stream! */
1184 c->switch_feed_streams[i] = -2;
1185 c->feed_streams[i] = -2;
1190 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1191 action_required = 1;
1194 return action_required;
1197 /* XXX: factorize in utils.c ? */
1198 /* XXX: take care with different space meaning */
1199 static void skip_spaces(const char **pp)
1203 while (*p == ' ' || *p == '\t')
1208 static void get_word(char *buf, int buf_size, const char **pp)
1216 while (!isspace(*p) && *p != '\0') {
1217 if ((q - buf) < buf_size - 1)
1226 static void get_arg(char *buf, int buf_size, const char **pp)
1233 while (isspace(*p)) p++;
1236 if (*p == '\"' || *p == '\'')
1248 if ((q - buf) < buf_size - 1)
1253 if (quote && *p == quote)
1258 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1259 const char *p, const char *filename, int line_num)
1265 get_arg(arg, sizeof(arg), &p);
1266 if (strcasecmp(arg, "allow") == 0)
1267 acl.action = IP_ALLOW;
1268 else if (strcasecmp(arg, "deny") == 0)
1269 acl.action = IP_DENY;
1271 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1272 filename, line_num, arg);
1276 get_arg(arg, sizeof(arg), &p);
1278 if (resolve_host(&acl.first, arg) != 0) {
1279 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1280 filename, line_num, arg);
1283 acl.last = acl.first;
1285 get_arg(arg, sizeof(arg), &p);
1288 if (resolve_host(&acl.last, arg) != 0) {
1289 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1290 filename, line_num, arg);
1296 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1297 IPAddressACL **naclp = 0;
1303 naclp = &stream->acl;
1309 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1310 filename, line_num);
1316 naclp = &(*naclp)->next;
1324 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1329 IPAddressACL *acl = NULL;
1333 f = fopen(stream->dynamic_acl, "r");
1335 perror(stream->dynamic_acl);
1339 acl = av_mallocz(sizeof(IPAddressACL));
1343 if (fgets(line, sizeof(line), f) == NULL)
1349 if (*p == '\0' || *p == '#')
1351 get_arg(cmd, sizeof(cmd), &p);
1353 if (!strcasecmp(cmd, "ACL"))
1354 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1361 static void free_acl_list(IPAddressACL *in_acl)
1363 IPAddressACL *pacl,*pacl2;
1373 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1375 enum IPAddressAction last_action = IP_DENY;
1377 struct in_addr *src = &c->from_addr.sin_addr;
1378 unsigned long src_addr = src->s_addr;
1380 for (acl = in_acl; acl; acl = acl->next) {
1381 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1382 return (acl->action == IP_ALLOW) ? 1 : 0;
1383 last_action = acl->action;
1386 /* Nothing matched, so return not the last action */
1387 return (last_action == IP_DENY) ? 1 : 0;
1390 static int validate_acl(FFStream *stream, HTTPContext *c)
1396 /* if stream->acl is null validate_acl_list will return 1 */
1397 ret = validate_acl_list(stream->acl, c);
1399 if (stream->dynamic_acl[0]) {
1400 acl = parse_dynamic_acl(stream, c);
1402 ret = validate_acl_list(acl, c);
1410 /* compute the real filename of a file by matching it without its
1411 extensions to all the stream filenames */
1412 static void compute_real_filename(char *filename, int max_size)
1419 /* compute filename by matching without the file extensions */
1420 av_strlcpy(file1, filename, sizeof(file1));
1421 p = strrchr(file1, '.');
1424 for(stream = first_stream; stream != NULL; stream = stream->next) {
1425 av_strlcpy(file2, stream->filename, sizeof(file2));
1426 p = strrchr(file2, '.');
1429 if (!strcmp(file1, file2)) {
1430 av_strlcpy(filename, stream->filename, max_size);
1445 /* parse http request and prepare header */
1446 static int http_parse_request(HTTPContext *c)
1449 enum RedirType redir_type;
1451 char info[1024], filename[1024];
1455 const char *mime_type;
1459 char *useragent = 0;
1462 get_word(cmd, sizeof(cmd), (const char **)&p);
1463 av_strlcpy(c->method, cmd, sizeof(c->method));
1465 if (!strcmp(cmd, "GET"))
1467 else if (!strcmp(cmd, "POST"))
1472 get_word(url, sizeof(url), (const char **)&p);
1473 av_strlcpy(c->url, url, sizeof(c->url));
1475 get_word(protocol, sizeof(protocol), (const char **)&p);
1476 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1479 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1482 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1484 /* find the filename and the optional info string in the request */
1485 p = strchr(url, '?');
1487 av_strlcpy(info, p, sizeof(info));
1492 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1494 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1495 if (strncasecmp(p, "User-Agent:", 11) == 0) {
1497 if (*useragent && *useragent != '\n' && isspace(*useragent))
1501 p = strchr(p, '\n');
1508 redir_type = REDIR_NONE;
1509 if (av_match_ext(filename, "asx")) {
1510 redir_type = REDIR_ASX;
1511 filename[strlen(filename)-1] = 'f';
1512 } else if (av_match_ext(filename, "asf") &&
1513 (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1514 /* if this isn't WMP or lookalike, return the redirector file */
1515 redir_type = REDIR_ASF;
1516 } else if (av_match_ext(filename, "rpm,ram")) {
1517 redir_type = REDIR_RAM;
1518 strcpy(filename + strlen(filename)-2, "m");
1519 } else if (av_match_ext(filename, "rtsp")) {
1520 redir_type = REDIR_RTSP;
1521 compute_real_filename(filename, sizeof(filename) - 1);
1522 } else if (av_match_ext(filename, "sdp")) {
1523 redir_type = REDIR_SDP;
1524 compute_real_filename(filename, sizeof(filename) - 1);
1527 // "redirect" / request to index.html
1528 if (!strlen(filename))
1529 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1531 stream = first_stream;
1532 while (stream != NULL) {
1533 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1535 stream = stream->next;
1537 if (stream == NULL) {
1538 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1539 http_log("File '%s' not found\n", url);
1544 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1545 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1547 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1548 c->http_error = 301;
1550 q += snprintf(q, c->buffer_size,
1551 "HTTP/1.0 301 Moved\r\n"
1553 "Content-type: text/html\r\n"
1555 "<html><head><title>Moved</title></head><body>\r\n"
1556 "You should be <a href=\"%s\">redirected</a>.\r\n"
1557 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1558 /* prepare output buffer */
1559 c->buffer_ptr = c->buffer;
1561 c->state = HTTPSTATE_SEND_HEADER;
1565 /* If this is WMP, get the rate information */
1566 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1567 if (modify_current_stream(c, ratebuf)) {
1568 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1569 if (c->switch_feed_streams[i] >= 0)
1570 c->switch_feed_streams[i] = -1;
1575 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1576 current_bandwidth += stream->bandwidth;
1578 /* If already streaming this feed, do not let start another feeder. */
1579 if (stream->feed_opened) {
1580 snprintf(msg, sizeof(msg), "This feed is already being received.");
1581 http_log("Feed '%s' already being received\n", stream->feed_filename);
1585 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1586 c->http_error = 503;
1588 q += snprintf(q, c->buffer_size,
1589 "HTTP/1.0 503 Server too busy\r\n"
1590 "Content-type: text/html\r\n"
1592 "<html><head><title>Too busy</title></head><body>\r\n"
1593 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1594 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1595 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1596 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1597 /* prepare output buffer */
1598 c->buffer_ptr = c->buffer;
1600 c->state = HTTPSTATE_SEND_HEADER;
1604 if (redir_type != REDIR_NONE) {
1607 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1608 if (strncasecmp(p, "Host:", 5) == 0) {
1612 p = strchr(p, '\n');
1623 while (isspace(*hostinfo))
1626 eoh = strchr(hostinfo, '\n');
1628 if (eoh[-1] == '\r')
1631 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1632 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1633 hostbuf[eoh - hostinfo] = 0;
1635 c->http_error = 200;
1637 switch(redir_type) {
1639 q += snprintf(q, c->buffer_size,
1640 "HTTP/1.0 200 ASX Follows\r\n"
1641 "Content-type: video/x-ms-asf\r\n"
1643 "<ASX Version=\"3\">\r\n"
1644 //"<!-- Autogenerated by ffserver -->\r\n"
1645 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1646 "</ASX>\r\n", hostbuf, filename, info);
1649 q += snprintf(q, c->buffer_size,
1650 "HTTP/1.0 200 RAM Follows\r\n"
1651 "Content-type: audio/x-pn-realaudio\r\n"
1653 "# Autogenerated by ffserver\r\n"
1654 "http://%s/%s%s\r\n", hostbuf, filename, info);
1657 q += snprintf(q, c->buffer_size,
1658 "HTTP/1.0 200 ASF Redirect follows\r\n"
1659 "Content-type: video/x-ms-asf\r\n"
1662 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1666 char hostname[256], *p;
1667 /* extract only hostname */
1668 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1669 p = strrchr(hostname, ':');
1672 q += snprintf(q, c->buffer_size,
1673 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1674 /* XXX: incorrect mime type ? */
1675 "Content-type: application/x-rtsp\r\n"
1677 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1683 int sdp_data_size, len;
1684 struct sockaddr_in my_addr;
1686 q += snprintf(q, c->buffer_size,
1687 "HTTP/1.0 200 OK\r\n"
1688 "Content-type: application/sdp\r\n"
1691 len = sizeof(my_addr);
1692 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1694 /* XXX: should use a dynamic buffer */
1695 sdp_data_size = prepare_sdp_description(stream,
1698 if (sdp_data_size > 0) {
1699 memcpy(q, sdp_data, sdp_data_size);
1711 /* prepare output buffer */
1712 c->buffer_ptr = c->buffer;
1714 c->state = HTTPSTATE_SEND_HEADER;
1720 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1724 stream->conns_served++;
1726 /* XXX: add there authenticate and IP match */
1729 /* if post, it means a feed is being sent */
1730 if (!stream->is_feed) {
1731 /* However it might be a status report from WMP! Let us log the
1732 * data as it might come in handy one day. */
1736 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1737 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1741 if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1742 client_id = strtol(p + 18, 0, 10);
1743 p = strchr(p, '\n');
1751 char *eol = strchr(logline, '\n');
1756 if (eol[-1] == '\r')
1758 http_log("%.*s\n", (int) (eol - logline), logline);
1759 c->suppress_log = 1;
1764 http_log("\nGot request:\n%s\n", c->buffer);
1767 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1770 /* Now we have to find the client_id */
1771 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1772 if (wmpc->wmp_client_id == client_id)
1776 if (wmpc && modify_current_stream(wmpc, ratebuf))
1777 wmpc->switch_pending = 1;
1780 snprintf(msg, sizeof(msg), "POST command not handled");
1784 if (http_start_receive_data(c) < 0) {
1785 snprintf(msg, sizeof(msg), "could not open feed");
1789 c->state = HTTPSTATE_RECEIVE_DATA;
1794 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1795 http_log("\nGot request:\n%s\n", c->buffer);
1798 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1801 /* open input stream */
1802 if (open_input_stream(c, info) < 0) {
1803 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1807 /* prepare http header */
1809 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1810 mime_type = c->stream->fmt->mime_type;
1812 mime_type = "application/x-octet-stream";
1813 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1815 /* for asf, we need extra headers */
1816 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1817 /* Need to allocate a client id */
1819 c->wmp_client_id = av_lfg_get(&random_state);
1821 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);
1823 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1824 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1826 /* prepare output buffer */
1828 c->buffer_ptr = c->buffer;
1830 c->state = HTTPSTATE_SEND_HEADER;
1833 c->http_error = 404;
1835 q += snprintf(q, c->buffer_size,
1836 "HTTP/1.0 404 Not Found\r\n"
1837 "Content-type: text/html\r\n"
1840 "<head><title>404 Not Found</title></head>\n"
1843 /* prepare output buffer */
1844 c->buffer_ptr = c->buffer;
1846 c->state = HTTPSTATE_SEND_HEADER;
1850 c->http_error = 200; /* horrible : we use this value to avoid
1851 going to the send data state */
1852 c->state = HTTPSTATE_SEND_HEADER;
1856 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1858 static const char *suffix = " kMGTP";
1861 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1863 avio_printf(pb, "%"PRId64"%c", count, *s);
1866 static void compute_status(HTTPContext *c)
1875 if (avio_open_dyn_buf(&pb) < 0) {
1876 /* XXX: return an error ? */
1877 c->buffer_ptr = c->buffer;
1878 c->buffer_end = c->buffer;
1882 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1883 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1884 avio_printf(pb, "Pragma: no-cache\r\n");
1885 avio_printf(pb, "\r\n");
1887 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1888 if (c->stream->feed_filename[0])
1889 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1890 avio_printf(pb, "</head>\n<body>");
1891 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1893 avio_printf(pb, "<h2>Available Streams</h2>\n");
1894 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1895 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");
1896 stream = first_stream;
1897 while (stream != NULL) {
1898 char sfilename[1024];
1901 if (stream->feed != stream) {
1902 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1903 eosf = sfilename + strlen(sfilename);
1904 if (eosf - sfilename >= 4) {
1905 if (strcmp(eosf - 4, ".asf") == 0)
1906 strcpy(eosf - 4, ".asx");
1907 else if (strcmp(eosf - 3, ".rm") == 0)
1908 strcpy(eosf - 3, ".ram");
1909 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1910 /* generate a sample RTSP director if
1911 unicast. Generate an SDP redirector if
1913 eosf = strrchr(sfilename, '.');
1915 eosf = sfilename + strlen(sfilename);
1916 if (stream->is_multicast)
1917 strcpy(eosf, ".sdp");
1919 strcpy(eosf, ".rtsp");
1923 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1924 sfilename, stream->filename);
1925 avio_printf(pb, "<td align=right> %d <td align=right> ",
1926 stream->conns_served);
1927 fmt_bytecount(pb, stream->bytes_served);
1928 switch(stream->stream_type) {
1929 case STREAM_TYPE_LIVE: {
1930 int audio_bit_rate = 0;
1931 int video_bit_rate = 0;
1932 const char *audio_codec_name = "";
1933 const char *video_codec_name = "";
1934 const char *audio_codec_name_extra = "";
1935 const char *video_codec_name_extra = "";
1937 for(i=0;i<stream->nb_streams;i++) {
1938 AVStream *st = stream->streams[i];
1939 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1940 switch(st->codec->codec_type) {
1941 case AVMEDIA_TYPE_AUDIO:
1942 audio_bit_rate += st->codec->bit_rate;
1944 if (*audio_codec_name)
1945 audio_codec_name_extra = "...";
1946 audio_codec_name = codec->name;
1949 case AVMEDIA_TYPE_VIDEO:
1950 video_bit_rate += st->codec->bit_rate;
1952 if (*video_codec_name)
1953 video_codec_name_extra = "...";
1954 video_codec_name = codec->name;
1957 case AVMEDIA_TYPE_DATA:
1958 video_bit_rate += st->codec->bit_rate;
1964 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",
1967 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1968 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1970 avio_printf(pb, "<td>%s", stream->feed->filename);
1972 avio_printf(pb, "<td>%s", stream->feed_filename);
1973 avio_printf(pb, "\n");
1977 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1981 stream = stream->next;
1983 avio_printf(pb, "</table>\n");
1985 stream = first_stream;
1986 while (stream != NULL) {
1987 if (stream->feed == stream) {
1988 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1990 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1992 #if defined(linux) && !defined(CONFIG_NOCUTILS)
1997 /* This is somewhat linux specific I guess */
1998 snprintf(ps_cmd, sizeof(ps_cmd),
1999 "ps -o \"%%cpu,cputime\" --no-headers %d",
2002 pid_stat = popen(ps_cmd, "r");
2007 if (fscanf(pid_stat, "%10s %64s", cpuperc,
2009 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2017 avio_printf(pb, "<p>");
2019 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");
2021 for (i = 0; i < stream->nb_streams; i++) {
2022 AVStream *st = stream->streams[i];
2023 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2024 const char *type = "unknown";
2025 char parameters[64];
2029 switch(st->codec->codec_type) {
2030 case AVMEDIA_TYPE_AUDIO:
2032 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2034 case AVMEDIA_TYPE_VIDEO:
2036 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2037 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2042 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2043 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2045 avio_printf(pb, "</table>\n");
2048 stream = stream->next;
2051 /* connection status */
2052 avio_printf(pb, "<h2>Connection Status</h2>\n");
2054 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2055 nb_connections, nb_max_connections);
2057 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2058 current_bandwidth, max_bandwidth);
2060 avio_printf(pb, "<table>\n");
2061 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");
2062 c1 = first_http_ctx;
2064 while (c1 != NULL) {
2070 for (j = 0; j < c1->stream->nb_streams; j++) {
2071 if (!c1->stream->feed)
2072 bitrate += c1->stream->streams[j]->codec->bit_rate;
2073 else if (c1->feed_streams[j] >= 0)
2074 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2079 p = inet_ntoa(c1->from_addr.sin_addr);
2080 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2082 c1->stream ? c1->stream->filename : "",
2083 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2086 http_state[c1->state]);
2087 fmt_bytecount(pb, bitrate);
2088 avio_printf(pb, "<td align=right>");
2089 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2090 avio_printf(pb, "<td align=right>");
2091 fmt_bytecount(pb, c1->data_count);
2092 avio_printf(pb, "\n");
2095 avio_printf(pb, "</table>\n");
2100 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2101 avio_printf(pb, "</body>\n</html>\n");
2103 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2104 c->buffer_ptr = c->pb_buffer;
2105 c->buffer_end = c->pb_buffer + len;
2108 /* check if the parser needs to be opened for stream i */
2109 static void open_parser(AVFormatContext *s, int i)
2111 AVStream *st = s->streams[i];
2114 if (!st->codec->codec) {
2115 codec = avcodec_find_decoder(st->codec->codec_id);
2116 if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2117 st->codec->parse_only = 1;
2118 if (avcodec_open(st->codec, codec) < 0)
2119 st->codec->parse_only = 0;
2124 static int open_input_stream(HTTPContext *c, const char *info)
2127 char input_filename[1024];
2129 int buf_size, i, ret;
2132 /* find file name */
2133 if (c->stream->feed) {
2134 strcpy(input_filename, c->stream->feed->feed_filename);
2135 buf_size = FFM_PACKET_SIZE;
2136 /* compute position (absolute time) */
2137 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2138 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2140 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2141 int prebuffer = strtol(buf, 0, 10);
2142 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2144 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2146 strcpy(input_filename, c->stream->feed_filename);
2148 /* compute position (relative time) */
2149 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2150 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2155 if (input_filename[0] == '\0')
2159 if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
2160 buf_size, c->stream->ap_in)) < 0) {
2161 http_log("could not open %s: %d\n", input_filename, ret);
2164 s->flags |= AVFMT_FLAG_GENPTS;
2166 if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2167 http_log("Could not find stream info '%s'\n", input_filename);
2168 av_close_input_file(s);
2172 /* open each parser */
2173 for(i=0;i<s->nb_streams;i++)
2176 /* choose stream as clock source (we favorize video stream if
2177 present) for packet sending */
2178 c->pts_stream_index = 0;
2179 for(i=0;i<c->stream->nb_streams;i++) {
2180 if (c->pts_stream_index == 0 &&
2181 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2182 c->pts_stream_index = i;
2186 if (c->fmt_in->iformat->read_seek)
2187 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2188 /* set the start time (needed for maxtime and RTP packet timing) */
2189 c->start_time = cur_time;
2190 c->first_pts = AV_NOPTS_VALUE;
2194 /* return the server clock (in us) */
2195 static int64_t get_server_clock(HTTPContext *c)
2197 /* compute current pts value from system time */
2198 return (cur_time - c->start_time) * 1000;
2201 /* return the estimated time at which the current packet must be sent
2203 static int64_t get_packet_send_clock(HTTPContext *c)
2205 int bytes_left, bytes_sent, frame_bytes;
2207 frame_bytes = c->cur_frame_bytes;
2208 if (frame_bytes <= 0)
2211 bytes_left = c->buffer_end - c->buffer_ptr;
2212 bytes_sent = frame_bytes - bytes_left;
2213 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2218 static int http_prepare_data(HTTPContext *c)
2221 AVFormatContext *ctx;
2223 av_freep(&c->pb_buffer);
2225 case HTTPSTATE_SEND_DATA_HEADER:
2226 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2227 av_metadata_set2(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2228 av_metadata_set2(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2229 av_metadata_set2(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2230 av_metadata_set2(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2232 for(i=0;i<c->stream->nb_streams;i++) {
2235 st = av_mallocz(sizeof(AVStream));
2236 c->fmt_ctx.streams[i] = st;
2237 /* if file or feed, then just take streams from FFStream struct */
2238 if (!c->stream->feed ||
2239 c->stream->feed == c->stream)
2240 src = c->stream->streams[i];
2242 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2246 st->codec->frame_number = 0; /* XXX: should be done in
2247 AVStream, not in codec */
2249 /* set output format parameters */
2250 c->fmt_ctx.oformat = c->stream->fmt;
2251 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2253 c->got_key_frame = 0;
2255 /* prepare header and save header data in a stream */
2256 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2257 /* XXX: potential leak */
2260 c->fmt_ctx.pb->seekable = 0;
2263 * HACK to avoid mpeg ps muxer to spit many underflow errors
2264 * Default value from Libav
2265 * Try to set it use configuration option
2267 c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
2268 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2270 av_set_parameters(&c->fmt_ctx, NULL);
2271 if (av_write_header(&c->fmt_ctx) < 0) {
2272 http_log("Error writing output header\n");
2275 av_metadata_free(&c->fmt_ctx.metadata);
2277 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2278 c->buffer_ptr = c->pb_buffer;
2279 c->buffer_end = c->pb_buffer + len;
2281 c->state = HTTPSTATE_SEND_DATA;
2282 c->last_packet_sent = 0;
2284 case HTTPSTATE_SEND_DATA:
2285 /* find a new packet */
2286 /* read a packet from the input stream */
2287 if (c->stream->feed)
2288 ffm_set_write_index(c->fmt_in,
2289 c->stream->feed->feed_write_index,
2290 c->stream->feed->feed_size);
2292 if (c->stream->max_time &&
2293 c->stream->max_time + c->start_time - cur_time < 0)
2294 /* We have timed out */
2295 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2299 ret = av_read_frame(c->fmt_in, &pkt);
2301 if (c->stream->feed) {
2302 /* if coming from feed, it means we reached the end of the
2303 ffm file, so must wait for more data */
2304 c->state = HTTPSTATE_WAIT_FEED;
2305 return 1; /* state changed */
2306 } else if (ret == AVERROR(EAGAIN)) {
2307 /* input not ready, come back later */
2310 if (c->stream->loop) {
2311 av_close_input_file(c->fmt_in);
2313 if (open_input_stream(c, "") < 0)
2318 /* must send trailer now because eof or error */
2319 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2323 int source_index = pkt.stream_index;
2324 /* update first pts if needed */
2325 if (c->first_pts == AV_NOPTS_VALUE) {
2326 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2327 c->start_time = cur_time;
2329 /* send it to the appropriate stream */
2330 if (c->stream->feed) {
2331 /* if coming from a feed, select the right stream */
2332 if (c->switch_pending) {
2333 c->switch_pending = 0;
2334 for(i=0;i<c->stream->nb_streams;i++) {
2335 if (c->switch_feed_streams[i] == pkt.stream_index)
2336 if (pkt.flags & AV_PKT_FLAG_KEY)
2337 c->switch_feed_streams[i] = -1;
2338 if (c->switch_feed_streams[i] >= 0)
2339 c->switch_pending = 1;
2342 for(i=0;i<c->stream->nb_streams;i++) {
2343 if (c->stream->feed_streams[i] == pkt.stream_index) {
2344 AVStream *st = c->fmt_in->streams[source_index];
2345 pkt.stream_index = i;
2346 if (pkt.flags & AV_PKT_FLAG_KEY &&
2347 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2348 c->stream->nb_streams == 1))
2349 c->got_key_frame = 1;
2350 if (!c->stream->send_on_key || c->got_key_frame)
2355 AVCodecContext *codec;
2356 AVStream *ist, *ost;
2358 ist = c->fmt_in->streams[source_index];
2359 /* specific handling for RTP: we use several
2360 output stream (one for each RTP
2361 connection). XXX: need more abstract handling */
2362 if (c->is_packetized) {
2363 /* compute send time and duration */
2364 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2365 c->cur_pts -= c->first_pts;
2366 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2367 /* find RTP context */
2368 c->packet_stream_index = pkt.stream_index;
2369 ctx = c->rtp_ctx[c->packet_stream_index];
2371 av_free_packet(&pkt);
2374 codec = ctx->streams[0]->codec;
2375 /* only one stream per RTP connection */
2376 pkt.stream_index = 0;
2380 codec = ctx->streams[pkt.stream_index]->codec;
2383 if (c->is_packetized) {
2384 int max_packet_size;
2385 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2386 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2388 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2389 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2391 ret = avio_open_dyn_buf(&ctx->pb);
2394 /* XXX: potential leak */
2397 ost = ctx->streams[pkt.stream_index];
2399 ctx->pb->seekable = 0;
2400 if (pkt.dts != AV_NOPTS_VALUE)
2401 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2402 if (pkt.pts != AV_NOPTS_VALUE)
2403 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2404 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2405 if (av_write_frame(ctx, &pkt) < 0) {
2406 http_log("Error writing frame to output\n");
2407 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2410 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2411 c->cur_frame_bytes = len;
2412 c->buffer_ptr = c->pb_buffer;
2413 c->buffer_end = c->pb_buffer + len;
2415 codec->frame_number++;
2417 av_free_packet(&pkt);
2421 av_free_packet(&pkt);
2426 case HTTPSTATE_SEND_DATA_TRAILER:
2427 /* last packet test ? */
2428 if (c->last_packet_sent || c->is_packetized)
2431 /* prepare header */
2432 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2433 /* XXX: potential leak */
2436 c->fmt_ctx.pb->seekable = 0;
2437 av_write_trailer(ctx);
2438 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2439 c->buffer_ptr = c->pb_buffer;
2440 c->buffer_end = c->pb_buffer + len;
2442 c->last_packet_sent = 1;
2448 /* should convert the format at the same time */
2449 /* send data starting at c->buffer_ptr to the output connection
2450 (either UDP or TCP connection) */
2451 static int http_send_data(HTTPContext *c)
2456 if (c->buffer_ptr >= c->buffer_end) {
2457 ret = http_prepare_data(c);
2461 /* state change requested */
2464 if (c->is_packetized) {
2465 /* RTP data output */
2466 len = c->buffer_end - c->buffer_ptr;
2468 /* fail safe - should never happen */
2470 c->buffer_ptr = c->buffer_end;
2473 len = (c->buffer_ptr[0] << 24) |
2474 (c->buffer_ptr[1] << 16) |
2475 (c->buffer_ptr[2] << 8) |
2477 if (len > (c->buffer_end - c->buffer_ptr))
2479 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2480 /* nothing to send yet: we can wait */
2484 c->data_count += len;
2485 update_datarate(&c->datarate, c->data_count);
2487 c->stream->bytes_served += len;
2489 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2490 /* RTP packets are sent inside the RTSP TCP connection */
2492 int interleaved_index, size;
2494 HTTPContext *rtsp_c;
2497 /* if no RTSP connection left, error */
2500 /* if already sending something, then wait. */
2501 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2503 if (avio_open_dyn_buf(&pb) < 0)
2505 interleaved_index = c->packet_stream_index * 2;
2506 /* RTCP packets are sent at odd indexes */
2507 if (c->buffer_ptr[1] == 200)
2508 interleaved_index++;
2509 /* write RTSP TCP header */
2511 header[1] = interleaved_index;
2512 header[2] = len >> 8;
2514 avio_write(pb, header, 4);
2515 /* write RTP packet data */
2517 avio_write(pb, c->buffer_ptr, len);
2518 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2519 /* prepare asynchronous TCP sending */
2520 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2521 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2522 c->buffer_ptr += len;
2524 /* send everything we can NOW */
2525 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2526 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2528 rtsp_c->packet_buffer_ptr += len;
2529 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2530 /* if we could not send all the data, we will
2531 send it later, so a new state is needed to
2532 "lock" the RTSP TCP connection */
2533 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2536 /* all data has been sent */
2537 av_freep(&c->packet_buffer);
2539 /* send RTP packet directly in UDP */
2541 url_write(c->rtp_handles[c->packet_stream_index],
2542 c->buffer_ptr, len);
2543 c->buffer_ptr += len;
2544 /* here we continue as we can send several packets per 10 ms slot */
2547 /* TCP data output */
2548 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2550 if (ff_neterrno() != AVERROR(EAGAIN) &&
2551 ff_neterrno() != AVERROR(EINTR))
2552 /* error : close connection */
2557 c->buffer_ptr += len;
2559 c->data_count += len;
2560 update_datarate(&c->datarate, c->data_count);
2562 c->stream->bytes_served += len;
2570 static int http_start_receive_data(HTTPContext *c)
2574 if (c->stream->feed_opened)
2577 /* Don't permit writing to this one */
2578 if (c->stream->readonly)
2582 fd = open(c->stream->feed_filename, O_RDWR);
2584 http_log("Error opening feeder file: %s\n", strerror(errno));
2589 if (c->stream->truncate) {
2590 /* truncate feed file */
2591 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2592 ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2593 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2595 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2596 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2601 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2602 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2603 lseek(fd, 0, SEEK_SET);
2605 /* init buffer input */
2606 c->buffer_ptr = c->buffer;
2607 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2608 c->stream->feed_opened = 1;
2609 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2613 static int http_receive_data(HTTPContext *c)
2616 int len, loop_run = 0;
2618 while (c->chunked_encoding && !c->chunk_size &&
2619 c->buffer_end > c->buffer_ptr) {
2620 /* read chunk header, if present */
2621 len = recv(c->fd, c->buffer_ptr, 1, 0);
2624 if (ff_neterrno() != AVERROR(EAGAIN) &&
2625 ff_neterrno() != AVERROR(EINTR))
2626 /* error : close connection */
2629 } else if (len == 0) {
2630 /* end of connection : close it */
2632 } else if (c->buffer_ptr - c->buffer >= 2 &&
2633 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2634 c->chunk_size = strtol(c->buffer, 0, 16);
2635 if (c->chunk_size == 0) // end of stream
2637 c->buffer_ptr = c->buffer;
2639 } else if (++loop_run > 10) {
2640 /* no chunk header, abort */
2647 if (c->buffer_end > c->buffer_ptr) {
2648 len = recv(c->fd, c->buffer_ptr,
2649 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2651 if (ff_neterrno() != AVERROR(EAGAIN) &&
2652 ff_neterrno() != AVERROR(EINTR))
2653 /* error : close connection */
2655 } else if (len == 0)
2656 /* end of connection : close it */
2659 c->chunk_size -= len;
2660 c->buffer_ptr += len;
2661 c->data_count += len;
2662 update_datarate(&c->datarate, c->data_count);
2666 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2667 if (c->buffer[0] != 'f' ||
2668 c->buffer[1] != 'm') {
2669 http_log("Feed stream has become desynchronized -- disconnecting\n");
2674 if (c->buffer_ptr >= c->buffer_end) {
2675 FFStream *feed = c->stream;
2676 /* a packet has been received : write it in the store, except
2678 if (c->data_count > FFM_PACKET_SIZE) {
2680 // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2681 /* XXX: use llseek or url_seek */
2682 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2683 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2684 http_log("Error writing to feed file: %s\n", strerror(errno));
2688 feed->feed_write_index += FFM_PACKET_SIZE;
2689 /* update file size */
2690 if (feed->feed_write_index > c->stream->feed_size)
2691 feed->feed_size = feed->feed_write_index;
2693 /* handle wrap around if max file size reached */
2694 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2695 feed->feed_write_index = FFM_PACKET_SIZE;
2698 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2699 http_log("Error writing index to feed file: %s\n", strerror(errno));
2703 /* wake up any waiting connections */
2704 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2705 if (c1->state == HTTPSTATE_WAIT_FEED &&
2706 c1->stream->feed == c->stream->feed)
2707 c1->state = HTTPSTATE_SEND_DATA;
2710 /* We have a header in our hands that contains useful data */
2711 AVFormatContext *s = NULL;
2713 AVInputFormat *fmt_in;
2716 /* use feed output format name to find corresponding input format */
2717 fmt_in = av_find_input_format(feed->fmt->name);
2721 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2722 0, NULL, NULL, NULL, NULL);
2725 if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2730 /* Now we have the actual streams */
2731 if (s->nb_streams != feed->nb_streams) {
2732 av_close_input_stream(s);
2734 http_log("Feed '%s' stream number does not match registered feed\n",
2735 c->stream->feed_filename);
2739 for (i = 0; i < s->nb_streams; i++) {
2740 AVStream *fst = feed->streams[i];
2741 AVStream *st = s->streams[i];
2742 avcodec_copy_context(fst->codec, st->codec);
2745 av_close_input_stream(s);
2748 c->buffer_ptr = c->buffer;
2753 c->stream->feed_opened = 0;
2755 /* wake up any waiting connections to stop waiting for feed */
2756 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2757 if (c1->state == HTTPSTATE_WAIT_FEED &&
2758 c1->stream->feed == c->stream->feed)
2759 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2764 /********************************************************************/
2767 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2774 switch(error_number) {
2775 case RTSP_STATUS_OK:
2778 case RTSP_STATUS_METHOD:
2779 str = "Method Not Allowed";
2781 case RTSP_STATUS_BANDWIDTH:
2782 str = "Not Enough Bandwidth";
2784 case RTSP_STATUS_SESSION:
2785 str = "Session Not Found";
2787 case RTSP_STATUS_STATE:
2788 str = "Method Not Valid in This State";
2790 case RTSP_STATUS_AGGREGATE:
2791 str = "Aggregate operation not allowed";
2793 case RTSP_STATUS_ONLY_AGGREGATE:
2794 str = "Only aggregate operation allowed";
2796 case RTSP_STATUS_TRANSPORT:
2797 str = "Unsupported transport";
2799 case RTSP_STATUS_INTERNAL:
2800 str = "Internal Server Error";
2802 case RTSP_STATUS_SERVICE:
2803 str = "Service Unavailable";
2805 case RTSP_STATUS_VERSION:
2806 str = "RTSP Version not supported";
2809 str = "Unknown Error";
2813 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2814 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2816 /* output GMT time */
2819 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2820 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2823 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2825 rtsp_reply_header(c, error_number);
2826 avio_printf(c->pb, "\r\n");
2829 static int rtsp_parse_request(HTTPContext *c)
2831 const char *p, *p1, *p2;
2837 RTSPMessageHeader header1, *header = &header1;
2839 c->buffer_ptr[0] = '\0';
2842 get_word(cmd, sizeof(cmd), &p);
2843 get_word(url, sizeof(url), &p);
2844 get_word(protocol, sizeof(protocol), &p);
2846 av_strlcpy(c->method, cmd, sizeof(c->method));
2847 av_strlcpy(c->url, url, sizeof(c->url));
2848 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2850 if (avio_open_dyn_buf(&c->pb) < 0) {
2851 /* XXX: cannot do more */
2852 c->pb = NULL; /* safety */
2856 /* check version name */
2857 if (strcmp(protocol, "RTSP/1.0") != 0) {
2858 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2862 /* parse each header line */
2863 memset(header, 0, sizeof(*header));
2864 /* skip to next line */
2865 while (*p != '\n' && *p != '\0')
2869 while (*p != '\0') {
2870 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2874 if (p2 > p && p2[-1] == '\r')
2876 /* skip empty line */
2880 if (len > sizeof(line) - 1)
2881 len = sizeof(line) - 1;
2882 memcpy(line, p, len);
2884 ff_rtsp_parse_line(header, line, NULL, NULL);
2888 /* handle sequence number */
2889 c->seq = header->seq;
2891 if (!strcmp(cmd, "DESCRIBE"))
2892 rtsp_cmd_describe(c, url);
2893 else if (!strcmp(cmd, "OPTIONS"))
2894 rtsp_cmd_options(c, url);
2895 else if (!strcmp(cmd, "SETUP"))
2896 rtsp_cmd_setup(c, url, header);
2897 else if (!strcmp(cmd, "PLAY"))
2898 rtsp_cmd_play(c, url, header);
2899 else if (!strcmp(cmd, "PAUSE"))
2900 rtsp_cmd_pause(c, url, header);
2901 else if (!strcmp(cmd, "TEARDOWN"))
2902 rtsp_cmd_teardown(c, url, header);
2904 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2907 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2908 c->pb = NULL; /* safety */
2910 /* XXX: cannot do more */
2913 c->buffer_ptr = c->pb_buffer;
2914 c->buffer_end = c->pb_buffer + len;
2915 c->state = RTSPSTATE_SEND_REPLY;
2919 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2920 struct in_addr my_ip)
2922 AVFormatContext *avc;
2923 AVStream *avs = NULL;
2926 avc = avformat_alloc_context();
2930 av_metadata_set2(&avc->metadata, "title",
2931 stream->title[0] ? stream->title : "No Title", 0);
2932 avc->nb_streams = stream->nb_streams;
2933 if (stream->is_multicast) {
2934 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2935 inet_ntoa(stream->multicast_ip),
2936 stream->multicast_port, stream->multicast_ttl);
2938 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2941 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2942 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2944 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2945 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2948 for(i = 0; i < stream->nb_streams; i++) {
2949 avc->streams[i] = &avs[i];
2950 avc->streams[i]->codec = stream->streams[i]->codec;
2952 *pbuffer = av_mallocz(2048);
2953 av_sdp_create(&avc, 1, *pbuffer, 2048);
2956 av_free(avc->streams);
2957 av_metadata_free(&avc->metadata);
2961 return strlen(*pbuffer);
2964 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2966 // rtsp_reply_header(c, RTSP_STATUS_OK);
2967 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2968 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2969 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2970 avio_printf(c->pb, "\r\n");
2973 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2979 int content_length, len;
2980 struct sockaddr_in my_addr;
2982 /* find which url is asked */
2983 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2988 for(stream = first_stream; stream != NULL; stream = stream->next) {
2989 if (!stream->is_feed &&
2990 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2991 !strcmp(path, stream->filename)) {
2995 /* no stream found */
2996 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3000 /* prepare the media description in sdp format */
3002 /* get the host IP */
3003 len = sizeof(my_addr);
3004 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3005 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3006 if (content_length < 0) {
3007 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3010 rtsp_reply_header(c, RTSP_STATUS_OK);
3011 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3012 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3013 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3014 avio_printf(c->pb, "\r\n");
3015 avio_write(c->pb, content, content_length);
3019 static HTTPContext *find_rtp_session(const char *session_id)
3023 if (session_id[0] == '\0')
3026 for(c = first_http_ctx; c != NULL; c = c->next) {
3027 if (!strcmp(c->session_id, session_id))
3033 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3035 RTSPTransportField *th;
3038 for(i=0;i<h->nb_transports;i++) {
3039 th = &h->transports[i];
3040 if (th->lower_transport == lower_transport)
3046 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3047 RTSPMessageHeader *h)
3050 int stream_index, rtp_port, rtcp_port;
3055 RTSPTransportField *th;
3056 struct sockaddr_in dest_addr;
3057 RTSPActionServerSetup setup;
3059 /* find which url is asked */
3060 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3065 /* now check each stream */
3066 for(stream = first_stream; stream != NULL; stream = stream->next) {
3067 if (!stream->is_feed &&
3068 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3069 /* accept aggregate filenames only if single stream */
3070 if (!strcmp(path, stream->filename)) {
3071 if (stream->nb_streams != 1) {
3072 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3079 for(stream_index = 0; stream_index < stream->nb_streams;
3081 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3082 stream->filename, stream_index);
3083 if (!strcmp(path, buf))
3088 /* no stream found */
3089 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3093 /* generate session id if needed */
3094 if (h->session_id[0] == '\0')
3095 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3096 av_lfg_get(&random_state), av_lfg_get(&random_state));
3098 /* find rtp session, and create it if none found */
3099 rtp_c = find_rtp_session(h->session_id);
3101 /* always prefer UDP */
3102 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3104 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3106 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3111 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3112 th->lower_transport);
3114 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3118 /* open input stream */
3119 if (open_input_stream(rtp_c, "") < 0) {
3120 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3125 /* test if stream is OK (test needed because several SETUP needs
3126 to be done for a given file) */
3127 if (rtp_c->stream != stream) {
3128 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3132 /* test if stream is already set up */
3133 if (rtp_c->rtp_ctx[stream_index]) {
3134 rtsp_reply_error(c, RTSP_STATUS_STATE);
3138 /* check transport */
3139 th = find_transport(h, rtp_c->rtp_protocol);
3140 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3141 th->client_port_min <= 0)) {
3142 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3146 /* setup default options */
3147 setup.transport_option[0] = '\0';
3148 dest_addr = rtp_c->from_addr;
3149 dest_addr.sin_port = htons(th->client_port_min);
3152 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3153 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3157 /* now everything is OK, so we can send the connection parameters */
3158 rtsp_reply_header(c, RTSP_STATUS_OK);
3160 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3162 switch(rtp_c->rtp_protocol) {
3163 case RTSP_LOWER_TRANSPORT_UDP:
3164 rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3165 rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3166 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3167 "client_port=%d-%d;server_port=%d-%d",
3168 th->client_port_min, th->client_port_max,
3169 rtp_port, rtcp_port);
3171 case RTSP_LOWER_TRANSPORT_TCP:
3172 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3173 stream_index * 2, stream_index * 2 + 1);
3178 if (setup.transport_option[0] != '\0')
3179 avio_printf(c->pb, ";%s", setup.transport_option);
3180 avio_printf(c->pb, "\r\n");
3183 avio_printf(c->pb, "\r\n");
3187 /* find an rtp connection by using the session ID. Check consistency
3189 static HTTPContext *find_rtp_session_with_url(const char *url,
3190 const char *session_id)
3198 rtp_c = find_rtp_session(session_id);
3202 /* find which url is asked */
3203 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3207 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3208 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3209 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3210 rtp_c->stream->filename, s);
3211 if(!strncmp(path, buf, sizeof(buf))) {
3212 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3217 if (len > 0 && path[len - 1] == '/' &&
3218 !strncmp(path, rtp_c->stream->filename, len - 1))
3223 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3227 rtp_c = find_rtp_session_with_url(url, h->session_id);
3229 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3233 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3234 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3235 rtp_c->state != HTTPSTATE_READY) {
3236 rtsp_reply_error(c, RTSP_STATUS_STATE);
3240 rtp_c->state = HTTPSTATE_SEND_DATA;
3242 /* now everything is OK, so we can send the connection parameters */
3243 rtsp_reply_header(c, RTSP_STATUS_OK);
3245 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3246 avio_printf(c->pb, "\r\n");
3249 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3253 rtp_c = find_rtp_session_with_url(url, h->session_id);
3255 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3259 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3260 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3261 rtsp_reply_error(c, RTSP_STATUS_STATE);
3265 rtp_c->state = HTTPSTATE_READY;
3266 rtp_c->first_pts = AV_NOPTS_VALUE;
3267 /* now everything is OK, so we can send the connection parameters */
3268 rtsp_reply_header(c, RTSP_STATUS_OK);
3270 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3271 avio_printf(c->pb, "\r\n");
3274 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3277 char session_id[32];
3279 rtp_c = find_rtp_session_with_url(url, h->session_id);
3281 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3285 av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3287 /* abort the session */
3288 close_connection(rtp_c);
3290 /* now everything is OK, so we can send the connection parameters */
3291 rtsp_reply_header(c, RTSP_STATUS_OK);
3293 avio_printf(c->pb, "Session: %s\r\n", session_id);
3294 avio_printf(c->pb, "\r\n");
3298 /********************************************************************/
3301 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3302 FFStream *stream, const char *session_id,
3303 enum RTSPLowerTransport rtp_protocol)
3305 HTTPContext *c = NULL;
3306 const char *proto_str;
3308 /* XXX: should output a warning page when coming
3309 close to the connection limit */
3310 if (nb_connections >= nb_max_connections)
3313 /* add a new connection */
3314 c = av_mallocz(sizeof(HTTPContext));
3319 c->poll_entry = NULL;
3320 c->from_addr = *from_addr;
3321 c->buffer_size = IOBUFFER_INIT_SIZE;
3322 c->buffer = av_malloc(c->buffer_size);
3327 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3328 c->state = HTTPSTATE_READY;
3329 c->is_packetized = 1;
3330 c->rtp_protocol = rtp_protocol;
3332 /* protocol is shown in statistics */
3333 switch(c->rtp_protocol) {
3334 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3335 proto_str = "MCAST";
3337 case RTSP_LOWER_TRANSPORT_UDP:
3340 case RTSP_LOWER_TRANSPORT_TCP:
3347 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3348 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3350 current_bandwidth += stream->bandwidth;
3352 c->next = first_http_ctx;
3364 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3365 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3367 static int rtp_new_av_stream(HTTPContext *c,
3368 int stream_index, struct sockaddr_in *dest_addr,
3369 HTTPContext *rtsp_c)
3371 AVFormatContext *ctx;
3374 URLContext *h = NULL;
3376 int max_packet_size;
3378 /* now we can open the relevant output stream */
3379 ctx = avformat_alloc_context();
3382 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3384 st = av_mallocz(sizeof(AVStream));
3387 ctx->nb_streams = 1;
3388 ctx->streams[0] = st;
3390 if (!c->stream->feed ||
3391 c->stream->feed == c->stream)
3392 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3395 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3397 st->priv_data = NULL;
3399 /* build destination RTP address */
3400 ipaddr = inet_ntoa(dest_addr->sin_addr);
3402 switch(c->rtp_protocol) {
3403 case RTSP_LOWER_TRANSPORT_UDP:
3404 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3407 /* XXX: also pass as parameter to function ? */
3408 if (c->stream->is_multicast) {
3410 ttl = c->stream->multicast_ttl;
3413 snprintf(ctx->filename, sizeof(ctx->filename),
3414 "rtp://%s:%d?multicast=1&ttl=%d",
3415 ipaddr, ntohs(dest_addr->sin_port), ttl);
3417 snprintf(ctx->filename, sizeof(ctx->filename),
3418 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3421 if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
3423 c->rtp_handles[stream_index] = h;
3424 max_packet_size = url_get_max_packet_size(h);
3426 case RTSP_LOWER_TRANSPORT_TCP:
3429 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3435 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3436 ipaddr, ntohs(dest_addr->sin_port),
3437 c->stream->filename, stream_index, c->protocol);
3439 /* normally, no packets should be output here, but the packet size may be checked */
3440 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3441 /* XXX: close stream */
3444 av_set_parameters(ctx, NULL);
3445 if (av_write_header(ctx) < 0) {
3452 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3455 c->rtp_ctx[stream_index] = ctx;
3459 /********************************************************************/
3460 /* ffserver initialization */
3462 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3466 fst = av_mallocz(sizeof(AVStream));
3470 fst->codec= avcodec_alloc_context();
3471 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3472 if (codec->extradata_size) {
3473 fst->codec->extradata = av_malloc(codec->extradata_size);
3474 memcpy(fst->codec->extradata, codec->extradata,
3475 codec->extradata_size);
3478 /* live streams must use the actual feed's codec since it may be
3479 * updated later to carry extradata needed by the streams.
3483 fst->priv_data = av_mallocz(sizeof(FeedData));
3484 fst->index = stream->nb_streams;
3485 av_set_pts_info(fst, 33, 1, 90000);
3486 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3487 stream->streams[stream->nb_streams++] = fst;
3491 /* return the stream number in the feed */
3492 static int add_av_stream(FFStream *feed, AVStream *st)
3495 AVCodecContext *av, *av1;
3499 for(i=0;i<feed->nb_streams;i++) {
3500 st = feed->streams[i];
3502 if (av1->codec_id == av->codec_id &&
3503 av1->codec_type == av->codec_type &&
3504 av1->bit_rate == av->bit_rate) {
3506 switch(av->codec_type) {
3507 case AVMEDIA_TYPE_AUDIO:
3508 if (av1->channels == av->channels &&
3509 av1->sample_rate == av->sample_rate)
3512 case AVMEDIA_TYPE_VIDEO:
3513 if (av1->width == av->width &&
3514 av1->height == av->height &&
3515 av1->time_base.den == av->time_base.den &&
3516 av1->time_base.num == av->time_base.num &&
3517 av1->gop_size == av->gop_size)
3526 fst = add_av_stream1(feed, av, 0);
3529 return feed->nb_streams - 1;
3534 static void remove_stream(FFStream *stream)
3538 while (*ps != NULL) {
3546 /* specific mpeg4 handling : we extract the raw parameters */
3547 static void extract_mpeg4_header(AVFormatContext *infile)
3549 int mpeg4_count, i, size;
3555 for(i=0;i<infile->nb_streams;i++) {
3556 st = infile->streams[i];
3557 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3558 st->codec->extradata_size == 0) {
3565 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3566 while (mpeg4_count > 0) {
3567 if (av_read_packet(infile, &pkt) < 0)
3569 st = infile->streams[pkt.stream_index];
3570 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3571 st->codec->extradata_size == 0) {
3572 av_freep(&st->codec->extradata);
3573 /* fill extradata with the header */
3574 /* XXX: we make hard suppositions here ! */
3576 while (p < pkt.data + pkt.size - 4) {
3577 /* stop when vop header is found */
3578 if (p[0] == 0x00 && p[1] == 0x00 &&
3579 p[2] == 0x01 && p[3] == 0xb6) {
3580 size = p - pkt.data;
3581 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3582 st->codec->extradata = av_malloc(size);
3583 st->codec->extradata_size = size;
3584 memcpy(st->codec->extradata, pkt.data, size);
3591 av_free_packet(&pkt);
3595 /* compute the needed AVStream for each file */
3596 static void build_file_streams(void)
3598 FFStream *stream, *stream_next;
3599 AVFormatContext *infile;
3602 /* gather all streams */
3603 for(stream = first_stream; stream != NULL; stream = stream_next) {
3604 stream_next = stream->next;
3605 if (stream->stream_type == STREAM_TYPE_LIVE &&
3607 /* the stream comes from a file */
3608 /* try to open the file */
3610 stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3611 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3612 /* specific case : if transport stream output to RTP,
3613 we use a raw transport stream reader */
3614 stream->ap_in->mpeg2ts_raw = 1;
3615 stream->ap_in->mpeg2ts_compute_pcr = 1;
3618 http_log("Opening file '%s'\n", stream->feed_filename);
3619 if ((ret = av_open_input_file(&infile, stream->feed_filename,
3620 stream->ifmt, 0, stream->ap_in)) < 0) {
3621 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3622 /* remove stream (no need to spend more time on it) */
3624 remove_stream(stream);
3626 /* find all the AVStreams inside and reference them in
3628 if (av_find_stream_info(infile) < 0) {
3629 http_log("Could not find codec parameters from '%s'\n",
3630 stream->feed_filename);
3631 av_close_input_file(infile);
3634 extract_mpeg4_header(infile);
3636 for(i=0;i<infile->nb_streams;i++)
3637 add_av_stream1(stream, infile->streams[i]->codec, 1);
3639 av_close_input_file(infile);
3645 /* compute the needed AVStream for each feed */
3646 static void build_feed_streams(void)
3648 FFStream *stream, *feed;
3651 /* gather all streams */
3652 for(stream = first_stream; stream != NULL; stream = stream->next) {
3653 feed = stream->feed;
3655 if (!stream->is_feed) {
3656 /* we handle a stream coming from a feed */
3657 for(i=0;i<stream->nb_streams;i++)
3658 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3663 /* gather all streams */
3664 for(stream = first_stream; stream != NULL; stream = stream->next) {
3665 feed = stream->feed;
3667 if (stream->is_feed) {
3668 for(i=0;i<stream->nb_streams;i++)
3669 stream->feed_streams[i] = i;
3674 /* create feed files if needed */
3675 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3678 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3679 /* See if it matches */
3683 if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3684 /* Now see if it matches */
3685 if (s->nb_streams == feed->nb_streams) {
3687 for(i=0;i<s->nb_streams;i++) {
3689 sf = feed->streams[i];
3692 if (sf->index != ss->index ||
3694 http_log("Index & Id do not match for stream %d (%s)\n",
3695 i, feed->feed_filename);
3698 AVCodecContext *ccf, *ccs;
3702 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3704 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3705 http_log("Codecs do not match for stream %d\n", i);
3707 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3708 http_log("Codec bitrates do not match for stream %d\n", i);
3710 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3711 if (CHECK_CODEC(time_base.den) ||
3712 CHECK_CODEC(time_base.num) ||
3713 CHECK_CODEC(width) ||
3714 CHECK_CODEC(height)) {
3715 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3718 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3719 if (CHECK_CODEC(sample_rate) ||
3720 CHECK_CODEC(channels) ||
3721 CHECK_CODEC(frame_size)) {
3722 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3726 http_log("Unknown codec type\n");
3734 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3735 feed->feed_filename, s->nb_streams, feed->nb_streams);
3737 av_close_input_file(s);
3739 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3740 feed->feed_filename);
3743 if (feed->readonly) {
3744 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3745 feed->feed_filename);
3748 unlink(feed->feed_filename);
3751 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3752 AVFormatContext s1 = {0}, *s = &s1;
3754 if (feed->readonly) {
3755 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3756 feed->feed_filename);
3760 /* only write the header of the ffm file */
3761 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3762 http_log("Could not open output feed file '%s'\n",
3763 feed->feed_filename);
3766 s->oformat = feed->fmt;
3767 s->nb_streams = feed->nb_streams;
3768 for(i=0;i<s->nb_streams;i++) {
3770 st = feed->streams[i];
3773 av_set_parameters(s, NULL);
3774 if (av_write_header(s) < 0) {
3775 http_log("Container doesn't supports the required parameters\n");
3778 /* XXX: need better api */
3779 av_freep(&s->priv_data);
3782 /* get feed size and write index */
3783 fd = open(feed->feed_filename, O_RDONLY);
3785 http_log("Could not open output feed file '%s'\n",
3786 feed->feed_filename);
3790 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3791 feed->feed_size = lseek(fd, 0, SEEK_END);
3792 /* ensure that we do not wrap before the end of file */
3793 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3794 feed->feed_max_size = feed->feed_size;
3800 /* compute the bandwidth used by each stream */
3801 static void compute_bandwidth(void)
3807 for(stream = first_stream; stream != NULL; stream = stream->next) {
3809 for(i=0;i<stream->nb_streams;i++) {
3810 AVStream *st = stream->streams[i];
3811 switch(st->codec->codec_type) {
3812 case AVMEDIA_TYPE_AUDIO:
3813 case AVMEDIA_TYPE_VIDEO:
3814 bandwidth += st->codec->bit_rate;
3820 stream->bandwidth = (bandwidth + 999) / 1000;
3824 /* add a codec and set the default parameters */
3825 static void add_codec(FFStream *stream, AVCodecContext *av)
3829 /* compute default parameters */
3830 switch(av->codec_type) {
3831 case AVMEDIA_TYPE_AUDIO:
3832 if (av->bit_rate == 0)
3833 av->bit_rate = 64000;
3834 if (av->sample_rate == 0)
3835 av->sample_rate = 22050;
3836 if (av->channels == 0)
3839 case AVMEDIA_TYPE_VIDEO:
3840 if (av->bit_rate == 0)
3841 av->bit_rate = 64000;
3842 if (av->time_base.num == 0){
3843 av->time_base.den = 5;
3844 av->time_base.num = 1;
3846 if (av->width == 0 || av->height == 0) {
3850 /* Bitrate tolerance is less for streaming */
3851 if (av->bit_rate_tolerance == 0)
3852 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3853 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3858 if (av->max_qdiff == 0)
3860 av->qcompress = 0.5;
3863 if (!av->nsse_weight)
3864 av->nsse_weight = 8;
3866 av->frame_skip_cmp = FF_CMP_DCTMAX;
3868 av->me_method = ME_EPZS;
3869 av->rc_buffer_aggressivity = 1.0;
3872 av->rc_eq = "tex^qComp";
3873 if (!av->i_quant_factor)
3874 av->i_quant_factor = -0.8;
3875 if (!av->b_quant_factor)
3876 av->b_quant_factor = 1.25;
3877 if (!av->b_quant_offset)
3878 av->b_quant_offset = 1.25;
3879 if (!av->rc_max_rate)
3880 av->rc_max_rate = av->bit_rate * 2;
3882 if (av->rc_max_rate && !av->rc_buffer_size) {
3883 av->rc_buffer_size = av->rc_max_rate;
3892 st = av_mallocz(sizeof(AVStream));
3895 st->codec = avcodec_alloc_context();
3896 stream->streams[stream->nb_streams++] = st;
3897 memcpy(st->codec, av, sizeof(AVCodecContext));
3900 static enum CodecID opt_audio_codec(const char *arg)
3902 AVCodec *p= avcodec_find_encoder_by_name(arg);
3904 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3905 return CODEC_ID_NONE;
3910 static enum CodecID opt_video_codec(const char *arg)
3912 AVCodec *p= avcodec_find_encoder_by_name(arg);
3914 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3915 return CODEC_ID_NONE;
3920 /* simplistic plugin support */
3923 static void load_module(const char *filename)
3926 void (*init_func)(void);
3927 dll = dlopen(filename, RTLD_NOW);
3929 fprintf(stderr, "Could not load module '%s' - %s\n",
3930 filename, dlerror());
3934 init_func = dlsym(dll, "ffserver_module_init");
3937 "%s: init function 'ffserver_module_init()' not found\n",
3946 static int ffserver_opt_default(const char *opt, const char *arg,
3947 AVCodecContext *avctx, int type)
3950 const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3952 ret = av_set_string3(avctx, opt, arg, 1, NULL);
3956 static int ffserver_opt_preset(const char *arg,
3957 AVCodecContext *avctx, int type,
3958 enum CodecID *audio_id, enum CodecID *video_id)
3961 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3963 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3965 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3966 codec ? codec->name : NULL))) {
3967 fprintf(stderr, "File for preset '%s' not found\n", arg);
3972 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3973 if(line[0] == '#' && !e)
3975 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3977 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3981 if(!strcmp(tmp, "acodec")){
3982 *audio_id = opt_audio_codec(tmp2);
3983 }else if(!strcmp(tmp, "vcodec")){
3984 *video_id = opt_video_codec(tmp2);
3985 }else if(!strcmp(tmp, "scodec")){
3986 /* opt_subtitle_codec(tmp2); */
3987 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3988 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3999 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4000 const char *mime_type)
4002 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4005 AVOutputFormat *stream_fmt;
4006 char stream_format_name[64];
4008 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4009 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4018 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4022 fprintf(stderr, "%s:%d: ", filename, line_num);
4023 vfprintf(stderr, fmt, vl);
4029 static int parse_ffconfig(const char *filename)
4036 int val, errors, line_num;
4037 FFStream **last_stream, *stream, *redirect;
4038 FFStream **last_feed, *feed, *s;
4039 AVCodecContext audio_enc, video_enc;
4040 enum CodecID audio_id, video_id;
4042 f = fopen(filename, "r");
4050 first_stream = NULL;
4051 last_stream = &first_stream;
4053 last_feed = &first_feed;
4057 audio_id = CODEC_ID_NONE;
4058 video_id = CODEC_ID_NONE;
4060 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4062 if (fgets(line, sizeof(line), f) == NULL)
4068 if (*p == '\0' || *p == '#')
4071 get_arg(cmd, sizeof(cmd), &p);
4073 if (!strcasecmp(cmd, "Port")) {
4074 get_arg(arg, sizeof(arg), &p);
4076 if (val < 1 || val > 65536) {
4077 ERROR("Invalid_port: %s\n", arg);
4079 my_http_addr.sin_port = htons(val);
4080 } else if (!strcasecmp(cmd, "BindAddress")) {
4081 get_arg(arg, sizeof(arg), &p);
4082 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4083 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4085 } else if (!strcasecmp(cmd, "NoDaemon")) {
4086 ffserver_daemon = 0;
4087 } else if (!strcasecmp(cmd, "RTSPPort")) {
4088 get_arg(arg, sizeof(arg), &p);
4090 if (val < 1 || val > 65536) {
4091 ERROR("%s:%d: Invalid port: %s\n", arg);
4093 my_rtsp_addr.sin_port = htons(atoi(arg));
4094 } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4095 get_arg(arg, sizeof(arg), &p);
4096 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4097 ERROR("Invalid host/IP address: %s\n", arg);
4099 } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4100 get_arg(arg, sizeof(arg), &p);
4102 if (val < 1 || val > 65536) {
4103 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4105 nb_max_http_connections = val;
4106 } else if (!strcasecmp(cmd, "MaxClients")) {
4107 get_arg(arg, sizeof(arg), &p);
4109 if (val < 1 || val > nb_max_http_connections) {
4110 ERROR("Invalid MaxClients: %s\n", arg);
4112 nb_max_connections = val;
4114 } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4116 get_arg(arg, sizeof(arg), &p);
4118 if (llval < 10 || llval > 10000000) {
4119 ERROR("Invalid MaxBandwidth: %s\n", arg);
4121 max_bandwidth = llval;
4122 } else if (!strcasecmp(cmd, "CustomLog")) {
4123 if (!ffserver_debug)
4124 get_arg(logfilename, sizeof(logfilename), &p);
4125 } else if (!strcasecmp(cmd, "<Feed")) {
4126 /*********************************************/
4127 /* Feed related options */
4129 if (stream || feed) {
4130 ERROR("Already in a tag\n");
4132 feed = av_mallocz(sizeof(FFStream));
4133 get_arg(feed->filename, sizeof(feed->filename), &p);
4134 q = strrchr(feed->filename, '>');
4138 for (s = first_feed; s; s = s->next) {
4139 if (!strcmp(feed->filename, s->filename)) {
4140 ERROR("Feed '%s' already registered\n", s->filename);
4144 feed->fmt = av_guess_format("ffm", NULL, NULL);
4145 /* defaut feed file */
4146 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4147 "/tmp/%s.ffm", feed->filename);
4148 feed->feed_max_size = 5 * 1024 * 1024;
4150 feed->feed = feed; /* self feeding :-) */
4152 /* add in stream list */
4153 *last_stream = feed;
4154 last_stream = &feed->next;
4155 /* add in feed list */
4157 last_feed = &feed->next_feed;
4159 } else if (!strcasecmp(cmd, "Launch")) {
4163 feed->child_argv = av_mallocz(64 * sizeof(char *));
4165 for (i = 0; i < 62; i++) {
4166 get_arg(arg, sizeof(arg), &p);
4170 feed->child_argv[i] = av_strdup(arg);
4173 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4175 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4177 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4178 inet_ntoa(my_http_addr.sin_addr),
4179 ntohs(my_http_addr.sin_port), feed->filename);
4181 } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4183 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4185 } else if (stream) {
4186 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4188 } else if (!strcasecmp(cmd, "File")) {
4190 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4192 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4193 } else if (!strcasecmp(cmd, "Truncate")) {
4195 get_arg(arg, sizeof(arg), &p);
4196 feed->truncate = strtod(arg, NULL);
4198 } else if (!strcasecmp(cmd, "FileMaxSize")) {
4203 get_arg(arg, sizeof(arg), &p);
4205 fsize = strtod(p1, &p1);
4206 switch(toupper(*p1)) {
4211 fsize *= 1024 * 1024;
4214 fsize *= 1024 * 1024 * 1024;
4217 feed->feed_max_size = (int64_t)fsize;
4218 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4219 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4222 } else if (!strcasecmp(cmd, "</Feed>")) {
4224 ERROR("No corresponding <Feed> for </Feed>\n");
4227 } else if (!strcasecmp(cmd, "<Stream")) {
4228 /*********************************************/
4229 /* Stream related options */
4231 if (stream || feed) {
4232 ERROR("Already in a tag\n");
4235 stream = av_mallocz(sizeof(FFStream));
4236 get_arg(stream->filename, sizeof(stream->filename), &p);
4237 q = strrchr(stream->filename, '>');
4241 for (s = first_stream; s; s = s->next) {
4242 if (!strcmp(stream->filename, s->filename)) {
4243 ERROR("Stream '%s' already registered\n", s->filename);
4247 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4248 avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4249 avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4250 audio_id = CODEC_ID_NONE;
4251 video_id = CODEC_ID_NONE;
4253 audio_id = stream->fmt->audio_codec;
4254 video_id = stream->fmt->video_codec;
4257 *last_stream = stream;
4258 last_stream = &stream->next;
4260 } else if (!strcasecmp(cmd, "Feed")) {
4261 get_arg(arg, sizeof(arg), &p);
4266 while (sfeed != NULL) {
4267 if (!strcmp(sfeed->filename, arg))
4269 sfeed = sfeed->next_feed;
4272 ERROR("feed '%s' not defined\n", arg);
4274 stream->feed = sfeed;
4276 } else if (!strcasecmp(cmd, "Format")) {
4277 get_arg(arg, sizeof(arg), &p);
4279 if (!strcmp(arg, "status")) {
4280 stream->stream_type = STREAM_TYPE_STATUS;
4283 stream->stream_type = STREAM_TYPE_LIVE;
4284 /* jpeg cannot be used here, so use single frame jpeg */
4285 if (!strcmp(arg, "jpeg"))
4286 strcpy(arg, "mjpeg");
4287 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4289 ERROR("Unknown Format: %s\n", arg);
4293 audio_id = stream->fmt->audio_codec;
4294 video_id = stream->fmt->video_codec;
4297 } else if (!strcasecmp(cmd, "InputFormat")) {
4298 get_arg(arg, sizeof(arg), &p);
4300 stream->ifmt = av_find_input_format(arg);
4301 if (!stream->ifmt) {
4302 ERROR("Unknown input format: %s\n", arg);
4305 } else if (!strcasecmp(cmd, "FaviconURL")) {
4306 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4307 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4309 ERROR("FaviconURL only permitted for status streams\n");
4311 } else if (!strcasecmp(cmd, "Author")) {
4313 get_arg(stream->author, sizeof(stream->author), &p);
4314 } else if (!strcasecmp(cmd, "Comment")) {
4316 get_arg(stream->comment, sizeof(stream->comment), &p);
4317 } else if (!strcasecmp(cmd, "Copyright")) {
4319 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4320 } else if (!strcasecmp(cmd, "Title")) {
4322 get_arg(stream->title, sizeof(stream->title), &p);
4323 } else if (!strcasecmp(cmd, "Preroll")) {
4324 get_arg(arg, sizeof(arg), &p);
4326 stream->prebuffer = atof(arg) * 1000;
4327 } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4329 stream->send_on_key = 1;
4330 } else if (!strcasecmp(cmd, "AudioCodec")) {
4331 get_arg(arg, sizeof(arg), &p);
4332 audio_id = opt_audio_codec(arg);
4333 if (audio_id == CODEC_ID_NONE) {
4334 ERROR("Unknown AudioCodec: %s\n", arg);
4336 } else if (!strcasecmp(cmd, "VideoCodec")) {
4337 get_arg(arg, sizeof(arg), &p);
4338 video_id = opt_video_codec(arg);
4339 if (video_id == CODEC_ID_NONE) {
4340 ERROR("Unknown VideoCodec: %s\n", arg);
4342 } else if (!strcasecmp(cmd, "MaxTime")) {
4343 get_arg(arg, sizeof(arg), &p);
4345 stream->max_time = atof(arg) * 1000;
4346 } else if (!strcasecmp(cmd, "AudioBitRate")) {
4347 get_arg(arg, sizeof(arg), &p);
4349 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4350 } else if (!strcasecmp(cmd, "AudioChannels")) {
4351 get_arg(arg, sizeof(arg), &p);
4353 audio_enc.channels = atoi(arg);
4354 } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4355 get_arg(arg, sizeof(arg), &p);
4357 audio_enc.sample_rate = atoi(arg);
4358 } else if (!strcasecmp(cmd, "AudioQuality")) {
4359 get_arg(arg, sizeof(arg), &p);
4361 // audio_enc.quality = atof(arg) * 1000;
4363 } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4365 int minrate, maxrate;
4367 get_arg(arg, sizeof(arg), &p);
4369 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4370 video_enc.rc_min_rate = minrate * 1000;
4371 video_enc.rc_max_rate = maxrate * 1000;
4373 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4376 } else if (!strcasecmp(cmd, "Debug")) {
4378 get_arg(arg, sizeof(arg), &p);
4379 video_enc.debug = strtol(arg,0,0);
4381 } else if (!strcasecmp(cmd, "Strict")) {
4383 get_arg(arg, sizeof(arg), &p);
4384 video_enc.strict_std_compliance = atoi(arg);
4386 } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4388 get_arg(arg, sizeof(arg), &p);
4389 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4391 } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4393 get_arg(arg, sizeof(arg), &p);
4394 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4396 } else if (!strcasecmp(cmd, "VideoBitRate")) {
4397 get_arg(arg, sizeof(arg), &p);
4399 video_enc.bit_rate = atoi(arg) * 1000;
4401 } else if (!strcasecmp(cmd, "VideoSize")) {
4402 get_arg(arg, sizeof(arg), &p);
4404 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4405 if ((video_enc.width % 16) != 0 ||
4406 (video_enc.height % 16) != 0) {
4407 ERROR("Image size must be a multiple of 16\n");
4410 } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4411 get_arg(arg, sizeof(arg), &p);
4413 AVRational frame_rate;
4414 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4415 ERROR("Incorrect frame rate: %s\n", arg);
4417 video_enc.time_base.num = frame_rate.den;
4418 video_enc.time_base.den = frame_rate.num;
4421 } else if (!strcasecmp(cmd, "VideoGopSize")) {
4422 get_arg(arg, sizeof(arg), &p);
4424 video_enc.gop_size = atoi(arg);
4425 } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4427 video_enc.gop_size = 1;
4428 } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4430 video_enc.mb_decision = FF_MB_DECISION_BITS;
4431 } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4433 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4434 video_enc.flags |= CODEC_FLAG_4MV;
4436 } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4437 !strcasecmp(cmd, "AVOptionAudio")) {
4439 AVCodecContext *avctx;
4441 get_arg(arg, sizeof(arg), &p);
4442 get_arg(arg2, sizeof(arg2), &p);
4443 if (!strcasecmp(cmd, "AVOptionVideo")) {
4445 type = AV_OPT_FLAG_VIDEO_PARAM;
4448 type = AV_OPT_FLAG_AUDIO_PARAM;
4450 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4451 ERROR("AVOption error: %s %s\n", arg, arg2);
4453 } else if (!strcasecmp(cmd, "AVPresetVideo") ||
4454 !strcasecmp(cmd, "AVPresetAudio")) {
4455 AVCodecContext *avctx;
4457 get_arg(arg, sizeof(arg), &p);
4458 if (!strcasecmp(cmd, "AVPresetVideo")) {
4460 video_enc.codec_id = video_id;
4461 type = AV_OPT_FLAG_VIDEO_PARAM;
4464 audio_enc.codec_id = audio_id;
4465 type = AV_OPT_FLAG_AUDIO_PARAM;
4467 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4468 ERROR("AVPreset error: %s\n", arg);
4470 } else if (!strcasecmp(cmd, "VideoTag")) {
4471 get_arg(arg, sizeof(arg), &p);
4472 if ((strlen(arg) == 4) && stream)
4473 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4474 } else if (!strcasecmp(cmd, "BitExact")) {
4476 video_enc.flags |= CODEC_FLAG_BITEXACT;
4477 } else if (!strcasecmp(cmd, "DctFastint")) {
4479 video_enc.dct_algo = FF_DCT_FASTINT;
4480 } else if (!strcasecmp(cmd, "IdctSimple")) {
4482 video_enc.idct_algo = FF_IDCT_SIMPLE;
4483 } else if (!strcasecmp(cmd, "Qscale")) {
4484 get_arg(arg, sizeof(arg), &p);
4486 video_enc.flags |= CODEC_FLAG_QSCALE;
4487 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4489 } else if (!strcasecmp(cmd, "VideoQDiff")) {
4490 get_arg(arg, sizeof(arg), &p);
4492 video_enc.max_qdiff = atoi(arg);
4493 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4494 ERROR("VideoQDiff out of range\n");
4497 } else if (!strcasecmp(cmd, "VideoQMax")) {
4498 get_arg(arg, sizeof(arg), &p);
4500 video_enc.qmax = atoi(arg);
4501 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4502 ERROR("VideoQMax out of range\n");
4505 } else if (!strcasecmp(cmd, "VideoQMin")) {
4506 get_arg(arg, sizeof(arg), &p);
4508 video_enc.qmin = atoi(arg);
4509 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4510 ERROR("VideoQMin out of range\n");
4513 } else if (!strcasecmp(cmd, "LumaElim")) {
4514 get_arg(arg, sizeof(arg), &p);
4516 video_enc.luma_elim_threshold = atoi(arg);
4517 } else if (!strcasecmp(cmd, "ChromaElim")) {
4518 get_arg(arg, sizeof(arg), &p);
4520 video_enc.chroma_elim_threshold = atoi(arg);
4521 } else if (!strcasecmp(cmd, "LumiMask")) {
4522 get_arg(arg, sizeof(arg), &p);
4524 video_enc.lumi_masking = atof(arg);
4525 } else if (!strcasecmp(cmd, "DarkMask")) {
4526 get_arg(arg, sizeof(arg), &p);
4528 video_enc.dark_masking = atof(arg);
4529 } else if (!strcasecmp(cmd, "NoVideo")) {
4530 video_id = CODEC_ID_NONE;
4531 } else if (!strcasecmp(cmd, "NoAudio")) {
4532 audio_id = CODEC_ID_NONE;
4533 } else if (!strcasecmp(cmd, "ACL")) {
4534 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4535 } else if (!strcasecmp(cmd, "DynamicACL")) {
4537 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4539 } else if (!strcasecmp(cmd, "RTSPOption")) {
4540 get_arg(arg, sizeof(arg), &p);
4542 av_freep(&stream->rtsp_option);
4543 stream->rtsp_option = av_strdup(arg);
4545 } else if (!strcasecmp(cmd, "MulticastAddress")) {
4546 get_arg(arg, sizeof(arg), &p);
4548 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4549 ERROR("Invalid host/IP address: %s\n", arg);
4551 stream->is_multicast = 1;
4552 stream->loop = 1; /* default is looping */
4554 } else if (!strcasecmp(cmd, "MulticastPort")) {
4555 get_arg(arg, sizeof(arg), &p);
4557 stream->multicast_port = atoi(arg);
4558 } else if (!strcasecmp(cmd, "MulticastTTL")) {
4559 get_arg(arg, sizeof(arg), &p);
4561 stream->multicast_ttl = atoi(arg);
4562 } else if (!strcasecmp(cmd, "NoLoop")) {
4565 } else if (!strcasecmp(cmd, "</Stream>")) {
4567 ERROR("No corresponding <Stream> for </Stream>\n");
4569 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4570 if (audio_id != CODEC_ID_NONE) {
4571 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4572 audio_enc.codec_id = audio_id;
4573 add_codec(stream, &audio_enc);
4575 if (video_id != CODEC_ID_NONE) {
4576 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4577 video_enc.codec_id = video_id;
4578 add_codec(stream, &video_enc);
4583 } else if (!strcasecmp(cmd, "<Redirect")) {
4584 /*********************************************/
4586 if (stream || feed || redirect) {
4587 ERROR("Already in a tag\n");
4589 redirect = av_mallocz(sizeof(FFStream));
4590 *last_stream = redirect;
4591 last_stream = &redirect->next;
4593 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4594 q = strrchr(redirect->filename, '>');
4597 redirect->stream_type = STREAM_TYPE_REDIRECT;
4599 } else if (!strcasecmp(cmd, "URL")) {
4601 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4602 } else if (!strcasecmp(cmd, "</Redirect>")) {
4604 ERROR("No corresponding <Redirect> for </Redirect>\n");
4606 if (!redirect->feed_filename[0]) {
4607 ERROR("No URL found for <Redirect>\n");
4611 } else if (!strcasecmp(cmd, "LoadModule")) {
4612 get_arg(arg, sizeof(arg), &p);
4616 ERROR("Module support not compiled into this version: '%s'\n", arg);
4619 ERROR("Incorrect keyword: '%s'\n", cmd);
4631 static void handle_child_exit(int sig)
4636 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4639 for (feed = first_feed; feed; feed = feed->next) {
4640 if (feed->pid == pid) {
4641 int uptime = time(0) - feed->pid_start;
4644 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4647 /* Turn off any more restarts */
4648 feed->child_argv = 0;
4653 need_to_start_children = 1;
4656 static void opt_debug(void)
4659 ffserver_daemon = 0;
4660 logfilename[0] = '-';
4663 static void show_help(void)
4665 printf("usage: ffserver [options]\n"
4666 "Hyper fast multi format Audio/Video streaming server\n");
4668 show_help_options(options, "Main options:\n", 0, 0);
4671 static const OptionDef options[] = {
4672 #include "cmdutils_common_opts.h"
4673 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4674 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4675 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4679 int main(int argc, char **argv)
4681 struct sigaction sigact;
4687 my_program_name = argv[0];
4688 my_program_dir = getcwd(0, 0);
4689 ffserver_daemon = 1;
4691 parse_options(argc, argv, options, NULL);
4693 unsetenv("http_proxy"); /* Kill the http_proxy */
4695 av_lfg_init(&random_state, av_get_random_seed());
4697 memset(&sigact, 0, sizeof(sigact));
4698 sigact.sa_handler = handle_child_exit;
4699 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4700 sigaction(SIGCHLD, &sigact, 0);
4702 if (parse_ffconfig(config_filename) < 0) {
4703 fprintf(stderr, "Incorrect config file - exiting.\n");
4707 /* open log file if needed */
4708 if (logfilename[0] != '\0') {
4709 if (!strcmp(logfilename, "-"))
4712 logfile = fopen(logfilename, "a");
4713 av_log_set_callback(http_av_log);
4716 build_file_streams();
4718 build_feed_streams();
4720 compute_bandwidth();
4722 /* put the process in background and detach it from its TTY */
4723 if (ffserver_daemon) {
4730 } else if (pid > 0) {
4737 open("/dev/null", O_RDWR);
4738 if (strcmp(logfilename, "-") != 0) {
4748 signal(SIGPIPE, SIG_IGN);
4750 if (ffserver_daemon)
4753 if (http_server() < 0) {
4754 http_log("Could not start server\n");