2 * Multiple format streaming server
3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #define closesocket close
29 #include "libavformat/avformat.h"
30 #include "libavformat/ffm.h"
31 #include "libavformat/network.h"
32 #include "libavformat/os_support.h"
33 #include "libavformat/rtpdec.h"
34 #include "libavformat/rtsp.h"
35 // XXX for ffio_open_dyn_packet_buffer, to be removed
36 #include "libavformat/avio_internal.h"
37 #include "libavutil/avstring.h"
38 #include "libavutil/lfg.h"
39 #include "libavutil/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 c->fmt_ctx.streams = av_mallocz(sizeof(*c->fmt_ctx.streams) * c->stream->nb_streams);
2233 for(i=0;i<c->stream->nb_streams;i++) {
2236 st = av_mallocz(sizeof(AVStream));
2237 c->fmt_ctx.streams[i] = st;
2238 /* if file or feed, then just take streams from FFStream struct */
2239 if (!c->stream->feed ||
2240 c->stream->feed == c->stream)
2241 src = c->stream->streams[i];
2243 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2247 st->codec->frame_number = 0; /* XXX: should be done in
2248 AVStream, not in codec */
2250 /* set output format parameters */
2251 c->fmt_ctx.oformat = c->stream->fmt;
2252 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2254 c->got_key_frame = 0;
2256 /* prepare header and save header data in a stream */
2257 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2258 /* XXX: potential leak */
2261 c->fmt_ctx.pb->seekable = 0;
2264 * HACK to avoid mpeg ps muxer to spit many underflow errors
2265 * Default value from FFmpeg
2266 * Try to set it use configuration option
2268 c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
2269 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2271 av_set_parameters(&c->fmt_ctx, NULL);
2272 if (av_write_header(&c->fmt_ctx) < 0) {
2273 http_log("Error writing output header\n");
2276 av_metadata_free(&c->fmt_ctx.metadata);
2278 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2279 c->buffer_ptr = c->pb_buffer;
2280 c->buffer_end = c->pb_buffer + len;
2282 c->state = HTTPSTATE_SEND_DATA;
2283 c->last_packet_sent = 0;
2285 case HTTPSTATE_SEND_DATA:
2286 /* find a new packet */
2287 /* read a packet from the input stream */
2288 if (c->stream->feed)
2289 ffm_set_write_index(c->fmt_in,
2290 c->stream->feed->feed_write_index,
2291 c->stream->feed->feed_size);
2293 if (c->stream->max_time &&
2294 c->stream->max_time + c->start_time - cur_time < 0)
2295 /* We have timed out */
2296 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2300 ret = av_read_frame(c->fmt_in, &pkt);
2302 if (c->stream->feed) {
2303 /* if coming from feed, it means we reached the end of the
2304 ffm file, so must wait for more data */
2305 c->state = HTTPSTATE_WAIT_FEED;
2306 return 1; /* state changed */
2307 } else if (ret == AVERROR(EAGAIN)) {
2308 /* input not ready, come back later */
2311 if (c->stream->loop) {
2312 av_close_input_file(c->fmt_in);
2314 if (open_input_stream(c, "") < 0)
2319 /* must send trailer now because eof or error */
2320 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2324 int source_index = pkt.stream_index;
2325 /* update first pts if needed */
2326 if (c->first_pts == AV_NOPTS_VALUE) {
2327 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2328 c->start_time = cur_time;
2330 /* send it to the appropriate stream */
2331 if (c->stream->feed) {
2332 /* if coming from a feed, select the right stream */
2333 if (c->switch_pending) {
2334 c->switch_pending = 0;
2335 for(i=0;i<c->stream->nb_streams;i++) {
2336 if (c->switch_feed_streams[i] == pkt.stream_index)
2337 if (pkt.flags & AV_PKT_FLAG_KEY)
2338 c->switch_feed_streams[i] = -1;
2339 if (c->switch_feed_streams[i] >= 0)
2340 c->switch_pending = 1;
2343 for(i=0;i<c->stream->nb_streams;i++) {
2344 if (c->stream->feed_streams[i] == pkt.stream_index) {
2345 AVStream *st = c->fmt_in->streams[source_index];
2346 pkt.stream_index = i;
2347 if (pkt.flags & AV_PKT_FLAG_KEY &&
2348 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2349 c->stream->nb_streams == 1))
2350 c->got_key_frame = 1;
2351 if (!c->stream->send_on_key || c->got_key_frame)
2356 AVCodecContext *codec;
2357 AVStream *ist, *ost;
2359 ist = c->fmt_in->streams[source_index];
2360 /* specific handling for RTP: we use several
2361 output stream (one for each RTP
2362 connection). XXX: need more abstract handling */
2363 if (c->is_packetized) {
2364 /* compute send time and duration */
2365 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2366 c->cur_pts -= c->first_pts;
2367 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2368 /* find RTP context */
2369 c->packet_stream_index = pkt.stream_index;
2370 ctx = c->rtp_ctx[c->packet_stream_index];
2372 av_free_packet(&pkt);
2375 codec = ctx->streams[0]->codec;
2376 /* only one stream per RTP connection */
2377 pkt.stream_index = 0;
2381 codec = ctx->streams[pkt.stream_index]->codec;
2384 if (c->is_packetized) {
2385 int max_packet_size;
2386 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2387 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2389 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2390 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2392 ret = avio_open_dyn_buf(&ctx->pb);
2395 /* XXX: potential leak */
2398 ost = ctx->streams[pkt.stream_index];
2400 ctx->pb->seekable = 0;
2401 if (pkt.dts != AV_NOPTS_VALUE)
2402 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2403 if (pkt.pts != AV_NOPTS_VALUE)
2404 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2405 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2406 if (av_write_frame(ctx, &pkt) < 0) {
2407 http_log("Error writing frame to output\n");
2408 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2411 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2412 c->cur_frame_bytes = len;
2413 c->buffer_ptr = c->pb_buffer;
2414 c->buffer_end = c->pb_buffer + len;
2416 codec->frame_number++;
2418 av_free_packet(&pkt);
2422 av_free_packet(&pkt);
2427 case HTTPSTATE_SEND_DATA_TRAILER:
2428 /* last packet test ? */
2429 if (c->last_packet_sent || c->is_packetized)
2432 /* prepare header */
2433 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2434 /* XXX: potential leak */
2437 c->fmt_ctx.pb->seekable = 0;
2438 av_write_trailer(ctx);
2439 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2440 c->buffer_ptr = c->pb_buffer;
2441 c->buffer_end = c->pb_buffer + len;
2443 c->last_packet_sent = 1;
2449 /* should convert the format at the same time */
2450 /* send data starting at c->buffer_ptr to the output connection
2451 (either UDP or TCP connection) */
2452 static int http_send_data(HTTPContext *c)
2457 if (c->buffer_ptr >= c->buffer_end) {
2458 ret = http_prepare_data(c);
2462 /* state change requested */
2465 if (c->is_packetized) {
2466 /* RTP data output */
2467 len = c->buffer_end - c->buffer_ptr;
2469 /* fail safe - should never happen */
2471 c->buffer_ptr = c->buffer_end;
2474 len = (c->buffer_ptr[0] << 24) |
2475 (c->buffer_ptr[1] << 16) |
2476 (c->buffer_ptr[2] << 8) |
2478 if (len > (c->buffer_end - c->buffer_ptr))
2480 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2481 /* nothing to send yet: we can wait */
2485 c->data_count += len;
2486 update_datarate(&c->datarate, c->data_count);
2488 c->stream->bytes_served += len;
2490 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2491 /* RTP packets are sent inside the RTSP TCP connection */
2493 int interleaved_index, size;
2495 HTTPContext *rtsp_c;
2498 /* if no RTSP connection left, error */
2501 /* if already sending something, then wait. */
2502 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2504 if (avio_open_dyn_buf(&pb) < 0)
2506 interleaved_index = c->packet_stream_index * 2;
2507 /* RTCP packets are sent at odd indexes */
2508 if (c->buffer_ptr[1] == 200)
2509 interleaved_index++;
2510 /* write RTSP TCP header */
2512 header[1] = interleaved_index;
2513 header[2] = len >> 8;
2515 avio_write(pb, header, 4);
2516 /* write RTP packet data */
2518 avio_write(pb, c->buffer_ptr, len);
2519 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2520 /* prepare asynchronous TCP sending */
2521 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2522 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2523 c->buffer_ptr += len;
2525 /* send everything we can NOW */
2526 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2527 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2529 rtsp_c->packet_buffer_ptr += len;
2530 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2531 /* if we could not send all the data, we will
2532 send it later, so a new state is needed to
2533 "lock" the RTSP TCP connection */
2534 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2537 /* all data has been sent */
2538 av_freep(&c->packet_buffer);
2540 /* send RTP packet directly in UDP */
2542 url_write(c->rtp_handles[c->packet_stream_index],
2543 c->buffer_ptr, len);
2544 c->buffer_ptr += len;
2545 /* here we continue as we can send several packets per 10 ms slot */
2548 /* TCP data output */
2549 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2551 if (ff_neterrno() != AVERROR(EAGAIN) &&
2552 ff_neterrno() != AVERROR(EINTR))
2553 /* error : close connection */
2558 c->buffer_ptr += len;
2560 c->data_count += len;
2561 update_datarate(&c->datarate, c->data_count);
2563 c->stream->bytes_served += len;
2571 static int http_start_receive_data(HTTPContext *c)
2575 if (c->stream->feed_opened)
2578 /* Don't permit writing to this one */
2579 if (c->stream->readonly)
2583 fd = open(c->stream->feed_filename, O_RDWR);
2585 http_log("Error opening feeder file: %s\n", strerror(errno));
2590 if (c->stream->truncate) {
2591 /* truncate feed file */
2592 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2593 ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2594 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2596 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2597 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2602 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2603 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2604 lseek(fd, 0, SEEK_SET);
2606 /* init buffer input */
2607 c->buffer_ptr = c->buffer;
2608 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2609 c->stream->feed_opened = 1;
2610 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2614 static int http_receive_data(HTTPContext *c)
2617 int len, loop_run = 0;
2619 while (c->chunked_encoding && !c->chunk_size &&
2620 c->buffer_end > c->buffer_ptr) {
2621 /* read chunk header, if present */
2622 len = recv(c->fd, c->buffer_ptr, 1, 0);
2625 if (ff_neterrno() != AVERROR(EAGAIN) &&
2626 ff_neterrno() != AVERROR(EINTR))
2627 /* error : close connection */
2630 } else if (len == 0) {
2631 /* end of connection : close it */
2633 } else if (c->buffer_ptr - c->buffer >= 2 &&
2634 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2635 c->chunk_size = strtol(c->buffer, 0, 16);
2636 if (c->chunk_size == 0) // end of stream
2638 c->buffer_ptr = c->buffer;
2640 } else if (++loop_run > 10) {
2641 /* no chunk header, abort */
2648 if (c->buffer_end > c->buffer_ptr) {
2649 len = recv(c->fd, c->buffer_ptr,
2650 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2652 if (ff_neterrno() != AVERROR(EAGAIN) &&
2653 ff_neterrno() != AVERROR(EINTR))
2654 /* error : close connection */
2656 } else if (len == 0)
2657 /* end of connection : close it */
2660 c->chunk_size -= len;
2661 c->buffer_ptr += len;
2662 c->data_count += len;
2663 update_datarate(&c->datarate, c->data_count);
2667 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2668 if (c->buffer[0] != 'f' ||
2669 c->buffer[1] != 'm') {
2670 http_log("Feed stream has become desynchronized -- disconnecting\n");
2675 if (c->buffer_ptr >= c->buffer_end) {
2676 FFStream *feed = c->stream;
2677 /* a packet has been received : write it in the store, except
2679 if (c->data_count > FFM_PACKET_SIZE) {
2681 // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2682 /* XXX: use llseek or url_seek */
2683 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2684 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2685 http_log("Error writing to feed file: %s\n", strerror(errno));
2689 feed->feed_write_index += FFM_PACKET_SIZE;
2690 /* update file size */
2691 if (feed->feed_write_index > c->stream->feed_size)
2692 feed->feed_size = feed->feed_write_index;
2694 /* handle wrap around if max file size reached */
2695 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2696 feed->feed_write_index = FFM_PACKET_SIZE;
2699 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2700 http_log("Error writing index to feed file: %s\n", strerror(errno));
2704 /* wake up any waiting connections */
2705 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2706 if (c1->state == HTTPSTATE_WAIT_FEED &&
2707 c1->stream->feed == c->stream->feed)
2708 c1->state = HTTPSTATE_SEND_DATA;
2711 /* We have a header in our hands that contains useful data */
2712 AVFormatContext *s = NULL;
2714 AVInputFormat *fmt_in;
2717 /* use feed output format name to find corresponding input format */
2718 fmt_in = av_find_input_format(feed->fmt->name);
2722 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2723 0, NULL, NULL, NULL, NULL);
2726 if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2731 /* Now we have the actual streams */
2732 if (s->nb_streams != feed->nb_streams) {
2733 av_close_input_stream(s);
2735 http_log("Feed '%s' stream number does not match registered feed\n",
2736 c->stream->feed_filename);
2740 for (i = 0; i < s->nb_streams; i++) {
2741 AVStream *fst = feed->streams[i];
2742 AVStream *st = s->streams[i];
2743 avcodec_copy_context(fst->codec, st->codec);
2746 av_close_input_stream(s);
2749 c->buffer_ptr = c->buffer;
2754 c->stream->feed_opened = 0;
2756 /* wake up any waiting connections to stop waiting for feed */
2757 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2758 if (c1->state == HTTPSTATE_WAIT_FEED &&
2759 c1->stream->feed == c->stream->feed)
2760 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2765 /********************************************************************/
2768 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2775 switch(error_number) {
2776 case RTSP_STATUS_OK:
2779 case RTSP_STATUS_METHOD:
2780 str = "Method Not Allowed";
2782 case RTSP_STATUS_BANDWIDTH:
2783 str = "Not Enough Bandwidth";
2785 case RTSP_STATUS_SESSION:
2786 str = "Session Not Found";
2788 case RTSP_STATUS_STATE:
2789 str = "Method Not Valid in This State";
2791 case RTSP_STATUS_AGGREGATE:
2792 str = "Aggregate operation not allowed";
2794 case RTSP_STATUS_ONLY_AGGREGATE:
2795 str = "Only aggregate operation allowed";
2797 case RTSP_STATUS_TRANSPORT:
2798 str = "Unsupported transport";
2800 case RTSP_STATUS_INTERNAL:
2801 str = "Internal Server Error";
2803 case RTSP_STATUS_SERVICE:
2804 str = "Service Unavailable";
2806 case RTSP_STATUS_VERSION:
2807 str = "RTSP Version not supported";
2810 str = "Unknown Error";
2814 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2815 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2817 /* output GMT time */
2820 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2821 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2824 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2826 rtsp_reply_header(c, error_number);
2827 avio_printf(c->pb, "\r\n");
2830 static int rtsp_parse_request(HTTPContext *c)
2832 const char *p, *p1, *p2;
2838 RTSPMessageHeader header1, *header = &header1;
2840 c->buffer_ptr[0] = '\0';
2843 get_word(cmd, sizeof(cmd), &p);
2844 get_word(url, sizeof(url), &p);
2845 get_word(protocol, sizeof(protocol), &p);
2847 av_strlcpy(c->method, cmd, sizeof(c->method));
2848 av_strlcpy(c->url, url, sizeof(c->url));
2849 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2851 if (avio_open_dyn_buf(&c->pb) < 0) {
2852 /* XXX: cannot do more */
2853 c->pb = NULL; /* safety */
2857 /* check version name */
2858 if (strcmp(protocol, "RTSP/1.0") != 0) {
2859 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2863 /* parse each header line */
2864 memset(header, 0, sizeof(*header));
2865 /* skip to next line */
2866 while (*p != '\n' && *p != '\0')
2870 while (*p != '\0') {
2871 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2875 if (p2 > p && p2[-1] == '\r')
2877 /* skip empty line */
2881 if (len > sizeof(line) - 1)
2882 len = sizeof(line) - 1;
2883 memcpy(line, p, len);
2885 ff_rtsp_parse_line(header, line, NULL, NULL);
2889 /* handle sequence number */
2890 c->seq = header->seq;
2892 if (!strcmp(cmd, "DESCRIBE"))
2893 rtsp_cmd_describe(c, url);
2894 else if (!strcmp(cmd, "OPTIONS"))
2895 rtsp_cmd_options(c, url);
2896 else if (!strcmp(cmd, "SETUP"))
2897 rtsp_cmd_setup(c, url, header);
2898 else if (!strcmp(cmd, "PLAY"))
2899 rtsp_cmd_play(c, url, header);
2900 else if (!strcmp(cmd, "PAUSE"))
2901 rtsp_cmd_pause(c, url, header);
2902 else if (!strcmp(cmd, "TEARDOWN"))
2903 rtsp_cmd_teardown(c, url, header);
2905 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2908 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2909 c->pb = NULL; /* safety */
2911 /* XXX: cannot do more */
2914 c->buffer_ptr = c->pb_buffer;
2915 c->buffer_end = c->pb_buffer + len;
2916 c->state = RTSPSTATE_SEND_REPLY;
2920 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2921 struct in_addr my_ip)
2923 AVFormatContext *avc;
2924 AVStream *avs = NULL;
2927 avc = avformat_alloc_context();
2931 av_metadata_set2(&avc->metadata, "title",
2932 stream->title[0] ? stream->title : "No Title", 0);
2933 avc->nb_streams = stream->nb_streams;
2934 if (stream->is_multicast) {
2935 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2936 inet_ntoa(stream->multicast_ip),
2937 stream->multicast_port, stream->multicast_ttl);
2939 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2942 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2943 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2945 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2946 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2949 for(i = 0; i < stream->nb_streams; i++) {
2950 avc->streams[i] = &avs[i];
2951 avc->streams[i]->codec = stream->streams[i]->codec;
2953 *pbuffer = av_mallocz(2048);
2954 av_sdp_create(&avc, 1, *pbuffer, 2048);
2957 av_free(avc->streams);
2958 av_metadata_free(&avc->metadata);
2962 return strlen(*pbuffer);
2965 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2967 // rtsp_reply_header(c, RTSP_STATUS_OK);
2968 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2969 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2970 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2971 avio_printf(c->pb, "\r\n");
2974 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2980 int content_length, len;
2981 struct sockaddr_in my_addr;
2983 /* find which url is asked */
2984 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2989 for(stream = first_stream; stream != NULL; stream = stream->next) {
2990 if (!stream->is_feed &&
2991 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2992 !strcmp(path, stream->filename)) {
2996 /* no stream found */
2997 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3001 /* prepare the media description in sdp format */
3003 /* get the host IP */
3004 len = sizeof(my_addr);
3005 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3006 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3007 if (content_length < 0) {
3008 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3011 rtsp_reply_header(c, RTSP_STATUS_OK);
3012 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3013 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3014 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3015 avio_printf(c->pb, "\r\n");
3016 avio_write(c->pb, content, content_length);
3020 static HTTPContext *find_rtp_session(const char *session_id)
3024 if (session_id[0] == '\0')
3027 for(c = first_http_ctx; c != NULL; c = c->next) {
3028 if (!strcmp(c->session_id, session_id))
3034 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3036 RTSPTransportField *th;
3039 for(i=0;i<h->nb_transports;i++) {
3040 th = &h->transports[i];
3041 if (th->lower_transport == lower_transport)
3047 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3048 RTSPMessageHeader *h)
3051 int stream_index, rtp_port, rtcp_port;
3056 RTSPTransportField *th;
3057 struct sockaddr_in dest_addr;
3058 RTSPActionServerSetup setup;
3060 /* find which url is asked */
3061 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3066 /* now check each stream */
3067 for(stream = first_stream; stream != NULL; stream = stream->next) {
3068 if (!stream->is_feed &&
3069 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3070 /* accept aggregate filenames only if single stream */
3071 if (!strcmp(path, stream->filename)) {
3072 if (stream->nb_streams != 1) {
3073 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3080 for(stream_index = 0; stream_index < stream->nb_streams;
3082 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3083 stream->filename, stream_index);
3084 if (!strcmp(path, buf))
3089 /* no stream found */
3090 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3094 /* generate session id if needed */
3095 if (h->session_id[0] == '\0')
3096 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3097 av_lfg_get(&random_state), av_lfg_get(&random_state));
3099 /* find rtp session, and create it if none found */
3100 rtp_c = find_rtp_session(h->session_id);
3102 /* always prefer UDP */
3103 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3105 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3107 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3112 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3113 th->lower_transport);
3115 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3119 /* open input stream */
3120 if (open_input_stream(rtp_c, "") < 0) {
3121 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3126 /* test if stream is OK (test needed because several SETUP needs
3127 to be done for a given file) */
3128 if (rtp_c->stream != stream) {
3129 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3133 /* test if stream is already set up */
3134 if (rtp_c->rtp_ctx[stream_index]) {
3135 rtsp_reply_error(c, RTSP_STATUS_STATE);
3139 /* check transport */
3140 th = find_transport(h, rtp_c->rtp_protocol);
3141 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3142 th->client_port_min <= 0)) {
3143 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3147 /* setup default options */
3148 setup.transport_option[0] = '\0';
3149 dest_addr = rtp_c->from_addr;
3150 dest_addr.sin_port = htons(th->client_port_min);
3153 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3154 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3158 /* now everything is OK, so we can send the connection parameters */
3159 rtsp_reply_header(c, RTSP_STATUS_OK);
3161 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3163 switch(rtp_c->rtp_protocol) {
3164 case RTSP_LOWER_TRANSPORT_UDP:
3165 rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3166 rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3167 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3168 "client_port=%d-%d;server_port=%d-%d",
3169 th->client_port_min, th->client_port_max,
3170 rtp_port, rtcp_port);
3172 case RTSP_LOWER_TRANSPORT_TCP:
3173 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3174 stream_index * 2, stream_index * 2 + 1);
3179 if (setup.transport_option[0] != '\0')
3180 avio_printf(c->pb, ";%s", setup.transport_option);
3181 avio_printf(c->pb, "\r\n");
3184 avio_printf(c->pb, "\r\n");
3188 /* find an rtp connection by using the session ID. Check consistency
3190 static HTTPContext *find_rtp_session_with_url(const char *url,
3191 const char *session_id)
3199 rtp_c = find_rtp_session(session_id);
3203 /* find which url is asked */
3204 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3208 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3209 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3210 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3211 rtp_c->stream->filename, s);
3212 if(!strncmp(path, buf, sizeof(buf))) {
3213 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3218 if (len > 0 && path[len - 1] == '/' &&
3219 !strncmp(path, rtp_c->stream->filename, len - 1))
3224 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3228 rtp_c = find_rtp_session_with_url(url, h->session_id);
3230 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3234 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3235 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3236 rtp_c->state != HTTPSTATE_READY) {
3237 rtsp_reply_error(c, RTSP_STATUS_STATE);
3241 rtp_c->state = HTTPSTATE_SEND_DATA;
3243 /* now everything is OK, so we can send the connection parameters */
3244 rtsp_reply_header(c, RTSP_STATUS_OK);
3246 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3247 avio_printf(c->pb, "\r\n");
3250 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3254 rtp_c = find_rtp_session_with_url(url, h->session_id);
3256 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3260 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3261 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3262 rtsp_reply_error(c, RTSP_STATUS_STATE);
3266 rtp_c->state = HTTPSTATE_READY;
3267 rtp_c->first_pts = AV_NOPTS_VALUE;
3268 /* now everything is OK, so we can send the connection parameters */
3269 rtsp_reply_header(c, RTSP_STATUS_OK);
3271 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3272 avio_printf(c->pb, "\r\n");
3275 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3278 char session_id[32];
3280 rtp_c = find_rtp_session_with_url(url, h->session_id);
3282 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3286 av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3288 /* abort the session */
3289 close_connection(rtp_c);
3291 /* now everything is OK, so we can send the connection parameters */
3292 rtsp_reply_header(c, RTSP_STATUS_OK);
3294 avio_printf(c->pb, "Session: %s\r\n", session_id);
3295 avio_printf(c->pb, "\r\n");
3299 /********************************************************************/
3302 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3303 FFStream *stream, const char *session_id,
3304 enum RTSPLowerTransport rtp_protocol)
3306 HTTPContext *c = NULL;
3307 const char *proto_str;
3309 /* XXX: should output a warning page when coming
3310 close to the connection limit */
3311 if (nb_connections >= nb_max_connections)
3314 /* add a new connection */
3315 c = av_mallocz(sizeof(HTTPContext));
3320 c->poll_entry = NULL;
3321 c->from_addr = *from_addr;
3322 c->buffer_size = IOBUFFER_INIT_SIZE;
3323 c->buffer = av_malloc(c->buffer_size);
3328 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3329 c->state = HTTPSTATE_READY;
3330 c->is_packetized = 1;
3331 c->rtp_protocol = rtp_protocol;
3333 /* protocol is shown in statistics */
3334 switch(c->rtp_protocol) {
3335 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3336 proto_str = "MCAST";
3338 case RTSP_LOWER_TRANSPORT_UDP:
3341 case RTSP_LOWER_TRANSPORT_TCP:
3348 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3349 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3351 current_bandwidth += stream->bandwidth;
3353 c->next = first_http_ctx;
3365 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3366 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3368 static int rtp_new_av_stream(HTTPContext *c,
3369 int stream_index, struct sockaddr_in *dest_addr,
3370 HTTPContext *rtsp_c)
3372 AVFormatContext *ctx;
3375 URLContext *h = NULL;
3377 int max_packet_size;
3379 /* now we can open the relevant output stream */
3380 ctx = avformat_alloc_context();
3383 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3385 st = av_mallocz(sizeof(AVStream));
3388 ctx->nb_streams = 1;
3389 ctx->streams[0] = st;
3391 if (!c->stream->feed ||
3392 c->stream->feed == c->stream)
3393 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3396 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3398 st->priv_data = NULL;
3400 /* build destination RTP address */
3401 ipaddr = inet_ntoa(dest_addr->sin_addr);
3403 switch(c->rtp_protocol) {
3404 case RTSP_LOWER_TRANSPORT_UDP:
3405 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3408 /* XXX: also pass as parameter to function ? */
3409 if (c->stream->is_multicast) {
3411 ttl = c->stream->multicast_ttl;
3414 snprintf(ctx->filename, sizeof(ctx->filename),
3415 "rtp://%s:%d?multicast=1&ttl=%d",
3416 ipaddr, ntohs(dest_addr->sin_port), ttl);
3418 snprintf(ctx->filename, sizeof(ctx->filename),
3419 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3422 if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
3424 c->rtp_handles[stream_index] = h;
3425 max_packet_size = url_get_max_packet_size(h);
3427 case RTSP_LOWER_TRANSPORT_TCP:
3430 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3436 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3437 ipaddr, ntohs(dest_addr->sin_port),
3438 c->stream->filename, stream_index, c->protocol);
3440 /* normally, no packets should be output here, but the packet size may be checked */
3441 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3442 /* XXX: close stream */
3445 av_set_parameters(ctx, NULL);
3446 if (av_write_header(ctx) < 0) {
3453 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3456 c->rtp_ctx[stream_index] = ctx;
3460 /********************************************************************/
3461 /* ffserver initialization */
3463 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3467 fst = av_mallocz(sizeof(AVStream));
3471 fst->codec= avcodec_alloc_context();
3472 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3473 if (codec->extradata_size) {
3474 fst->codec->extradata = av_malloc(codec->extradata_size);
3475 memcpy(fst->codec->extradata, codec->extradata,
3476 codec->extradata_size);
3479 /* live streams must use the actual feed's codec since it may be
3480 * updated later to carry extradata needed by the streams.
3484 fst->priv_data = av_mallocz(sizeof(FeedData));
3485 fst->index = stream->nb_streams;
3486 av_set_pts_info(fst, 33, 1, 90000);
3487 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3488 stream->streams[stream->nb_streams++] = fst;
3492 /* return the stream number in the feed */
3493 static int add_av_stream(FFStream *feed, AVStream *st)
3496 AVCodecContext *av, *av1;
3500 for(i=0;i<feed->nb_streams;i++) {
3501 st = feed->streams[i];
3503 if (av1->codec_id == av->codec_id &&
3504 av1->codec_type == av->codec_type &&
3505 av1->bit_rate == av->bit_rate) {
3507 switch(av->codec_type) {
3508 case AVMEDIA_TYPE_AUDIO:
3509 if (av1->channels == av->channels &&
3510 av1->sample_rate == av->sample_rate)
3513 case AVMEDIA_TYPE_VIDEO:
3514 if (av1->width == av->width &&
3515 av1->height == av->height &&
3516 av1->time_base.den == av->time_base.den &&
3517 av1->time_base.num == av->time_base.num &&
3518 av1->gop_size == av->gop_size)
3527 fst = add_av_stream1(feed, av, 0);
3530 return feed->nb_streams - 1;
3535 static void remove_stream(FFStream *stream)
3539 while (*ps != NULL) {
3547 /* specific mpeg4 handling : we extract the raw parameters */
3548 static void extract_mpeg4_header(AVFormatContext *infile)
3550 int mpeg4_count, i, size;
3556 for(i=0;i<infile->nb_streams;i++) {
3557 st = infile->streams[i];
3558 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3559 st->codec->extradata_size == 0) {
3566 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3567 while (mpeg4_count > 0) {
3568 if (av_read_packet(infile, &pkt) < 0)
3570 st = infile->streams[pkt.stream_index];
3571 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3572 st->codec->extradata_size == 0) {
3573 av_freep(&st->codec->extradata);
3574 /* fill extradata with the header */
3575 /* XXX: we make hard suppositions here ! */
3577 while (p < pkt.data + pkt.size - 4) {
3578 /* stop when vop header is found */
3579 if (p[0] == 0x00 && p[1] == 0x00 &&
3580 p[2] == 0x01 && p[3] == 0xb6) {
3581 size = p - pkt.data;
3582 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3583 st->codec->extradata = av_malloc(size);
3584 st->codec->extradata_size = size;
3585 memcpy(st->codec->extradata, pkt.data, size);
3592 av_free_packet(&pkt);
3596 /* compute the needed AVStream for each file */
3597 static void build_file_streams(void)
3599 FFStream *stream, *stream_next;
3600 AVFormatContext *infile;
3603 /* gather all streams */
3604 for(stream = first_stream; stream != NULL; stream = stream_next) {
3605 stream_next = stream->next;
3606 if (stream->stream_type == STREAM_TYPE_LIVE &&
3608 /* the stream comes from a file */
3609 /* try to open the file */
3611 stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3612 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3613 /* specific case : if transport stream output to RTP,
3614 we use a raw transport stream reader */
3615 stream->ap_in->mpeg2ts_raw = 1;
3616 stream->ap_in->mpeg2ts_compute_pcr = 1;
3619 http_log("Opening file '%s'\n", stream->feed_filename);
3620 if ((ret = av_open_input_file(&infile, stream->feed_filename,
3621 stream->ifmt, 0, stream->ap_in)) < 0) {
3622 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3623 /* remove stream (no need to spend more time on it) */
3625 remove_stream(stream);
3627 /* find all the AVStreams inside and reference them in
3629 if (av_find_stream_info(infile) < 0) {
3630 http_log("Could not find codec parameters from '%s'\n",
3631 stream->feed_filename);
3632 av_close_input_file(infile);
3635 extract_mpeg4_header(infile);
3637 for(i=0;i<infile->nb_streams;i++)
3638 add_av_stream1(stream, infile->streams[i]->codec, 1);
3640 av_close_input_file(infile);
3646 /* compute the needed AVStream for each feed */
3647 static void build_feed_streams(void)
3649 FFStream *stream, *feed;
3652 /* gather all streams */
3653 for(stream = first_stream; stream != NULL; stream = stream->next) {
3654 feed = stream->feed;
3656 if (!stream->is_feed) {
3657 /* we handle a stream coming from a feed */
3658 for(i=0;i<stream->nb_streams;i++)
3659 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3664 /* gather all streams */
3665 for(stream = first_stream; stream != NULL; stream = stream->next) {
3666 feed = stream->feed;
3668 if (stream->is_feed) {
3669 for(i=0;i<stream->nb_streams;i++)
3670 stream->feed_streams[i] = i;
3675 /* create feed files if needed */
3676 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3679 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3680 /* See if it matches */
3684 if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3685 /* Now see if it matches */
3686 if (s->nb_streams == feed->nb_streams) {
3688 for(i=0;i<s->nb_streams;i++) {
3690 sf = feed->streams[i];
3693 if (sf->index != ss->index ||
3695 http_log("Index & Id do not match for stream %d (%s)\n",
3696 i, feed->feed_filename);
3699 AVCodecContext *ccf, *ccs;
3703 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3705 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3706 http_log("Codecs do not match for stream %d\n", i);
3708 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3709 http_log("Codec bitrates do not match for stream %d\n", i);
3711 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3712 if (CHECK_CODEC(time_base.den) ||
3713 CHECK_CODEC(time_base.num) ||
3714 CHECK_CODEC(width) ||
3715 CHECK_CODEC(height)) {
3716 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3719 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3720 if (CHECK_CODEC(sample_rate) ||
3721 CHECK_CODEC(channels) ||
3722 CHECK_CODEC(frame_size)) {
3723 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3727 http_log("Unknown codec type\n");
3735 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3736 feed->feed_filename, s->nb_streams, feed->nb_streams);
3738 av_close_input_file(s);
3740 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3741 feed->feed_filename);
3744 if (feed->readonly) {
3745 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3746 feed->feed_filename);
3749 unlink(feed->feed_filename);
3752 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3753 AVFormatContext s1 = {0}, *s = &s1;
3755 if (feed->readonly) {
3756 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3757 feed->feed_filename);
3761 /* only write the header of the ffm file */
3762 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3763 http_log("Could not open output feed file '%s'\n",
3764 feed->feed_filename);
3767 s->oformat = feed->fmt;
3768 s->nb_streams = feed->nb_streams;
3769 for(i=0;i<s->nb_streams;i++) {
3771 st = feed->streams[i];
3774 av_set_parameters(s, NULL);
3775 if (av_write_header(s) < 0) {
3776 http_log("Container doesn't supports the required parameters\n");
3779 /* XXX: need better api */
3780 av_freep(&s->priv_data);
3783 /* get feed size and write index */
3784 fd = open(feed->feed_filename, O_RDONLY);
3786 http_log("Could not open output feed file '%s'\n",
3787 feed->feed_filename);
3791 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3792 feed->feed_size = lseek(fd, 0, SEEK_END);
3793 /* ensure that we do not wrap before the end of file */
3794 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3795 feed->feed_max_size = feed->feed_size;
3801 /* compute the bandwidth used by each stream */
3802 static void compute_bandwidth(void)
3808 for(stream = first_stream; stream != NULL; stream = stream->next) {
3810 for(i=0;i<stream->nb_streams;i++) {
3811 AVStream *st = stream->streams[i];
3812 switch(st->codec->codec_type) {
3813 case AVMEDIA_TYPE_AUDIO:
3814 case AVMEDIA_TYPE_VIDEO:
3815 bandwidth += st->codec->bit_rate;
3821 stream->bandwidth = (bandwidth + 999) / 1000;
3825 /* add a codec and set the default parameters */
3826 static void add_codec(FFStream *stream, AVCodecContext *av)
3830 /* compute default parameters */
3831 switch(av->codec_type) {
3832 case AVMEDIA_TYPE_AUDIO:
3833 if (av->bit_rate == 0)
3834 av->bit_rate = 64000;
3835 if (av->sample_rate == 0)
3836 av->sample_rate = 22050;
3837 if (av->channels == 0)
3840 case AVMEDIA_TYPE_VIDEO:
3841 if (av->bit_rate == 0)
3842 av->bit_rate = 64000;
3843 if (av->time_base.num == 0){
3844 av->time_base.den = 5;
3845 av->time_base.num = 1;
3847 if (av->width == 0 || av->height == 0) {
3851 /* Bitrate tolerance is less for streaming */
3852 if (av->bit_rate_tolerance == 0)
3853 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3854 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3859 if (av->max_qdiff == 0)
3861 av->qcompress = 0.5;
3864 if (!av->nsse_weight)
3865 av->nsse_weight = 8;
3867 av->frame_skip_cmp = FF_CMP_DCTMAX;
3869 av->me_method = ME_EPZS;
3870 av->rc_buffer_aggressivity = 1.0;
3873 av->rc_eq = "tex^qComp";
3874 if (!av->i_quant_factor)
3875 av->i_quant_factor = -0.8;
3876 if (!av->b_quant_factor)
3877 av->b_quant_factor = 1.25;
3878 if (!av->b_quant_offset)
3879 av->b_quant_offset = 1.25;
3880 if (!av->rc_max_rate)
3881 av->rc_max_rate = av->bit_rate * 2;
3883 if (av->rc_max_rate && !av->rc_buffer_size) {
3884 av->rc_buffer_size = av->rc_max_rate;
3893 st = av_mallocz(sizeof(AVStream));
3896 st->codec = avcodec_alloc_context();
3897 stream->streams[stream->nb_streams++] = st;
3898 memcpy(st->codec, av, sizeof(AVCodecContext));
3901 static enum CodecID opt_audio_codec(const char *arg)
3903 AVCodec *p= avcodec_find_encoder_by_name(arg);
3905 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3906 return CODEC_ID_NONE;
3911 static enum CodecID opt_video_codec(const char *arg)
3913 AVCodec *p= avcodec_find_encoder_by_name(arg);
3915 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3916 return CODEC_ID_NONE;
3921 /* simplistic plugin support */
3924 static void load_module(const char *filename)
3927 void (*init_func)(void);
3928 dll = dlopen(filename, RTLD_NOW);
3930 fprintf(stderr, "Could not load module '%s' - %s\n",
3931 filename, dlerror());
3935 init_func = dlsym(dll, "ffserver_module_init");
3938 "%s: init function 'ffserver_module_init()' not found\n",
3947 static int ffserver_opt_default(const char *opt, const char *arg,
3948 AVCodecContext *avctx, int type)
3951 const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3953 ret = av_set_string3(avctx, opt, arg, 1, NULL);
3957 static int ffserver_opt_preset(const char *arg,
3958 AVCodecContext *avctx, int type,
3959 enum CodecID *audio_id, enum CodecID *video_id)
3962 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3964 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3966 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3967 codec ? codec->name : NULL))) {
3968 fprintf(stderr, "File for preset '%s' not found\n", arg);
3973 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3974 if(line[0] == '#' && !e)
3976 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3978 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3982 if(!strcmp(tmp, "acodec")){
3983 *audio_id = opt_audio_codec(tmp2);
3984 }else if(!strcmp(tmp, "vcodec")){
3985 *video_id = opt_video_codec(tmp2);
3986 }else if(!strcmp(tmp, "scodec")){
3987 /* opt_subtitle_codec(tmp2); */
3988 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3989 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4000 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4001 const char *mime_type)
4003 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4006 AVOutputFormat *stream_fmt;
4007 char stream_format_name[64];
4009 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4010 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4019 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4023 fprintf(stderr, "%s:%d: ", filename, line_num);
4024 vfprintf(stderr, fmt, vl);
4030 static int parse_ffconfig(const char *filename)
4037 int val, errors, line_num;
4038 FFStream **last_stream, *stream, *redirect;
4039 FFStream **last_feed, *feed, *s;
4040 AVCodecContext audio_enc, video_enc;
4041 enum CodecID audio_id, video_id;
4043 f = fopen(filename, "r");
4051 first_stream = NULL;
4052 last_stream = &first_stream;
4054 last_feed = &first_feed;
4058 audio_id = CODEC_ID_NONE;
4059 video_id = CODEC_ID_NONE;
4061 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4063 if (fgets(line, sizeof(line), f) == NULL)
4069 if (*p == '\0' || *p == '#')
4072 get_arg(cmd, sizeof(cmd), &p);
4074 if (!strcasecmp(cmd, "Port")) {
4075 get_arg(arg, sizeof(arg), &p);
4077 if (val < 1 || val > 65536) {
4078 ERROR("Invalid_port: %s\n", arg);
4080 my_http_addr.sin_port = htons(val);
4081 } else if (!strcasecmp(cmd, "BindAddress")) {
4082 get_arg(arg, sizeof(arg), &p);
4083 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4084 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4086 } else if (!strcasecmp(cmd, "NoDaemon")) {
4087 ffserver_daemon = 0;
4088 } else if (!strcasecmp(cmd, "RTSPPort")) {
4089 get_arg(arg, sizeof(arg), &p);
4091 if (val < 1 || val > 65536) {
4092 ERROR("%s:%d: Invalid port: %s\n", arg);
4094 my_rtsp_addr.sin_port = htons(atoi(arg));
4095 } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4096 get_arg(arg, sizeof(arg), &p);
4097 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4098 ERROR("Invalid host/IP address: %s\n", arg);
4100 } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4101 get_arg(arg, sizeof(arg), &p);
4103 if (val < 1 || val > 65536) {
4104 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4106 nb_max_http_connections = val;
4107 } else if (!strcasecmp(cmd, "MaxClients")) {
4108 get_arg(arg, sizeof(arg), &p);
4110 if (val < 1 || val > nb_max_http_connections) {
4111 ERROR("Invalid MaxClients: %s\n", arg);
4113 nb_max_connections = val;
4115 } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4117 get_arg(arg, sizeof(arg), &p);
4119 if (llval < 10 || llval > 10000000) {
4120 ERROR("Invalid MaxBandwidth: %s\n", arg);
4122 max_bandwidth = llval;
4123 } else if (!strcasecmp(cmd, "CustomLog")) {
4124 if (!ffserver_debug)
4125 get_arg(logfilename, sizeof(logfilename), &p);
4126 } else if (!strcasecmp(cmd, "<Feed")) {
4127 /*********************************************/
4128 /* Feed related options */
4130 if (stream || feed) {
4131 ERROR("Already in a tag\n");
4133 feed = av_mallocz(sizeof(FFStream));
4134 get_arg(feed->filename, sizeof(feed->filename), &p);
4135 q = strrchr(feed->filename, '>');
4139 for (s = first_feed; s; s = s->next) {
4140 if (!strcmp(feed->filename, s->filename)) {
4141 ERROR("Feed '%s' already registered\n", s->filename);
4145 feed->fmt = av_guess_format("ffm", NULL, NULL);
4146 /* defaut feed file */
4147 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4148 "/tmp/%s.ffm", feed->filename);
4149 feed->feed_max_size = 5 * 1024 * 1024;
4151 feed->feed = feed; /* self feeding :-) */
4153 /* add in stream list */
4154 *last_stream = feed;
4155 last_stream = &feed->next;
4156 /* add in feed list */
4158 last_feed = &feed->next_feed;
4160 } else if (!strcasecmp(cmd, "Launch")) {
4164 feed->child_argv = av_mallocz(64 * sizeof(char *));
4166 for (i = 0; i < 62; i++) {
4167 get_arg(arg, sizeof(arg), &p);
4171 feed->child_argv[i] = av_strdup(arg);
4174 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4176 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4178 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4179 inet_ntoa(my_http_addr.sin_addr),
4180 ntohs(my_http_addr.sin_port), feed->filename);
4182 } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4184 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4186 } else if (stream) {
4187 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4189 } else if (!strcasecmp(cmd, "File")) {
4191 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4193 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4194 } else if (!strcasecmp(cmd, "Truncate")) {
4196 get_arg(arg, sizeof(arg), &p);
4197 feed->truncate = strtod(arg, NULL);
4199 } else if (!strcasecmp(cmd, "FileMaxSize")) {
4204 get_arg(arg, sizeof(arg), &p);
4206 fsize = strtod(p1, &p1);
4207 switch(toupper(*p1)) {
4212 fsize *= 1024 * 1024;
4215 fsize *= 1024 * 1024 * 1024;
4218 feed->feed_max_size = (int64_t)fsize;
4219 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4220 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4223 } else if (!strcasecmp(cmd, "</Feed>")) {
4225 ERROR("No corresponding <Feed> for </Feed>\n");
4228 } else if (!strcasecmp(cmd, "<Stream")) {
4229 /*********************************************/
4230 /* Stream related options */
4232 if (stream || feed) {
4233 ERROR("Already in a tag\n");
4236 stream = av_mallocz(sizeof(FFStream));
4237 get_arg(stream->filename, sizeof(stream->filename), &p);
4238 q = strrchr(stream->filename, '>');
4242 for (s = first_stream; s; s = s->next) {
4243 if (!strcmp(stream->filename, s->filename)) {
4244 ERROR("Stream '%s' already registered\n", s->filename);
4248 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4249 avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4250 avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4251 audio_id = CODEC_ID_NONE;
4252 video_id = CODEC_ID_NONE;
4254 audio_id = stream->fmt->audio_codec;
4255 video_id = stream->fmt->video_codec;
4258 *last_stream = stream;
4259 last_stream = &stream->next;
4261 } else if (!strcasecmp(cmd, "Feed")) {
4262 get_arg(arg, sizeof(arg), &p);
4267 while (sfeed != NULL) {
4268 if (!strcmp(sfeed->filename, arg))
4270 sfeed = sfeed->next_feed;
4273 ERROR("feed '%s' not defined\n", arg);
4275 stream->feed = sfeed;
4277 } else if (!strcasecmp(cmd, "Format")) {
4278 get_arg(arg, sizeof(arg), &p);
4280 if (!strcmp(arg, "status")) {
4281 stream->stream_type = STREAM_TYPE_STATUS;
4284 stream->stream_type = STREAM_TYPE_LIVE;
4285 /* jpeg cannot be used here, so use single frame jpeg */
4286 if (!strcmp(arg, "jpeg"))
4287 strcpy(arg, "mjpeg");
4288 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4290 ERROR("Unknown Format: %s\n", arg);
4294 audio_id = stream->fmt->audio_codec;
4295 video_id = stream->fmt->video_codec;
4298 } else if (!strcasecmp(cmd, "InputFormat")) {
4299 get_arg(arg, sizeof(arg), &p);
4301 stream->ifmt = av_find_input_format(arg);
4302 if (!stream->ifmt) {
4303 ERROR("Unknown input format: %s\n", arg);
4306 } else if (!strcasecmp(cmd, "FaviconURL")) {
4307 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4308 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4310 ERROR("FaviconURL only permitted for status streams\n");
4312 } else if (!strcasecmp(cmd, "Author")) {
4314 get_arg(stream->author, sizeof(stream->author), &p);
4315 } else if (!strcasecmp(cmd, "Comment")) {
4317 get_arg(stream->comment, sizeof(stream->comment), &p);
4318 } else if (!strcasecmp(cmd, "Copyright")) {
4320 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4321 } else if (!strcasecmp(cmd, "Title")) {
4323 get_arg(stream->title, sizeof(stream->title), &p);
4324 } else if (!strcasecmp(cmd, "Preroll")) {
4325 get_arg(arg, sizeof(arg), &p);
4327 stream->prebuffer = atof(arg) * 1000;
4328 } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4330 stream->send_on_key = 1;
4331 } else if (!strcasecmp(cmd, "AudioCodec")) {
4332 get_arg(arg, sizeof(arg), &p);
4333 audio_id = opt_audio_codec(arg);
4334 if (audio_id == CODEC_ID_NONE) {
4335 ERROR("Unknown AudioCodec: %s\n", arg);
4337 } else if (!strcasecmp(cmd, "VideoCodec")) {
4338 get_arg(arg, sizeof(arg), &p);
4339 video_id = opt_video_codec(arg);
4340 if (video_id == CODEC_ID_NONE) {
4341 ERROR("Unknown VideoCodec: %s\n", arg);
4343 } else if (!strcasecmp(cmd, "MaxTime")) {
4344 get_arg(arg, sizeof(arg), &p);
4346 stream->max_time = atof(arg) * 1000;
4347 } else if (!strcasecmp(cmd, "AudioBitRate")) {
4348 get_arg(arg, sizeof(arg), &p);
4350 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4351 } else if (!strcasecmp(cmd, "AudioChannels")) {
4352 get_arg(arg, sizeof(arg), &p);
4354 audio_enc.channels = atoi(arg);
4355 } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4356 get_arg(arg, sizeof(arg), &p);
4358 audio_enc.sample_rate = atoi(arg);
4359 } else if (!strcasecmp(cmd, "AudioQuality")) {
4360 get_arg(arg, sizeof(arg), &p);
4362 // audio_enc.quality = atof(arg) * 1000;
4364 } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4366 int minrate, maxrate;
4368 get_arg(arg, sizeof(arg), &p);
4370 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4371 video_enc.rc_min_rate = minrate * 1000;
4372 video_enc.rc_max_rate = maxrate * 1000;
4374 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4377 } else if (!strcasecmp(cmd, "Debug")) {
4379 get_arg(arg, sizeof(arg), &p);
4380 video_enc.debug = strtol(arg,0,0);
4382 } else if (!strcasecmp(cmd, "Strict")) {
4384 get_arg(arg, sizeof(arg), &p);
4385 video_enc.strict_std_compliance = atoi(arg);
4387 } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4389 get_arg(arg, sizeof(arg), &p);
4390 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4392 } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4394 get_arg(arg, sizeof(arg), &p);
4395 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4397 } else if (!strcasecmp(cmd, "VideoBitRate")) {
4398 get_arg(arg, sizeof(arg), &p);
4400 video_enc.bit_rate = atoi(arg) * 1000;
4402 } else if (!strcasecmp(cmd, "VideoSize")) {
4403 get_arg(arg, sizeof(arg), &p);
4405 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4406 if ((video_enc.width % 16) != 0 ||
4407 (video_enc.height % 16) != 0) {
4408 ERROR("Image size must be a multiple of 16\n");
4411 } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4412 get_arg(arg, sizeof(arg), &p);
4414 AVRational frame_rate;
4415 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4416 ERROR("Incorrect frame rate: %s\n", arg);
4418 video_enc.time_base.num = frame_rate.den;
4419 video_enc.time_base.den = frame_rate.num;
4422 } else if (!strcasecmp(cmd, "VideoGopSize")) {
4423 get_arg(arg, sizeof(arg), &p);
4425 video_enc.gop_size = atoi(arg);
4426 } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4428 video_enc.gop_size = 1;
4429 } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4431 video_enc.mb_decision = FF_MB_DECISION_BITS;
4432 } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4434 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4435 video_enc.flags |= CODEC_FLAG_4MV;
4437 } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4438 !strcasecmp(cmd, "AVOptionAudio")) {
4440 AVCodecContext *avctx;
4442 get_arg(arg, sizeof(arg), &p);
4443 get_arg(arg2, sizeof(arg2), &p);
4444 if (!strcasecmp(cmd, "AVOptionVideo")) {
4446 type = AV_OPT_FLAG_VIDEO_PARAM;
4449 type = AV_OPT_FLAG_AUDIO_PARAM;
4451 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4452 ERROR("AVOption error: %s %s\n", arg, arg2);
4454 } else if (!strcasecmp(cmd, "AVPresetVideo") ||
4455 !strcasecmp(cmd, "AVPresetAudio")) {
4456 AVCodecContext *avctx;
4458 get_arg(arg, sizeof(arg), &p);
4459 if (!strcasecmp(cmd, "AVPresetVideo")) {
4461 video_enc.codec_id = video_id;
4462 type = AV_OPT_FLAG_VIDEO_PARAM;
4465 audio_enc.codec_id = audio_id;
4466 type = AV_OPT_FLAG_AUDIO_PARAM;
4468 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4469 ERROR("AVPreset error: %s\n", arg);
4471 } else if (!strcasecmp(cmd, "VideoTag")) {
4472 get_arg(arg, sizeof(arg), &p);
4473 if ((strlen(arg) == 4) && stream)
4474 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4475 } else if (!strcasecmp(cmd, "BitExact")) {
4477 video_enc.flags |= CODEC_FLAG_BITEXACT;
4478 } else if (!strcasecmp(cmd, "DctFastint")) {
4480 video_enc.dct_algo = FF_DCT_FASTINT;
4481 } else if (!strcasecmp(cmd, "IdctSimple")) {
4483 video_enc.idct_algo = FF_IDCT_SIMPLE;
4484 } else if (!strcasecmp(cmd, "Qscale")) {
4485 get_arg(arg, sizeof(arg), &p);
4487 video_enc.flags |= CODEC_FLAG_QSCALE;
4488 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4490 } else if (!strcasecmp(cmd, "VideoQDiff")) {
4491 get_arg(arg, sizeof(arg), &p);
4493 video_enc.max_qdiff = atoi(arg);
4494 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4495 ERROR("VideoQDiff out of range\n");
4498 } else if (!strcasecmp(cmd, "VideoQMax")) {
4499 get_arg(arg, sizeof(arg), &p);
4501 video_enc.qmax = atoi(arg);
4502 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4503 ERROR("VideoQMax out of range\n");
4506 } else if (!strcasecmp(cmd, "VideoQMin")) {
4507 get_arg(arg, sizeof(arg), &p);
4509 video_enc.qmin = atoi(arg);
4510 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4511 ERROR("VideoQMin out of range\n");
4514 } else if (!strcasecmp(cmd, "LumaElim")) {
4515 get_arg(arg, sizeof(arg), &p);
4517 video_enc.luma_elim_threshold = atoi(arg);
4518 } else if (!strcasecmp(cmd, "ChromaElim")) {
4519 get_arg(arg, sizeof(arg), &p);
4521 video_enc.chroma_elim_threshold = atoi(arg);
4522 } else if (!strcasecmp(cmd, "LumiMask")) {
4523 get_arg(arg, sizeof(arg), &p);
4525 video_enc.lumi_masking = atof(arg);
4526 } else if (!strcasecmp(cmd, "DarkMask")) {
4527 get_arg(arg, sizeof(arg), &p);
4529 video_enc.dark_masking = atof(arg);
4530 } else if (!strcasecmp(cmd, "NoVideo")) {
4531 video_id = CODEC_ID_NONE;
4532 } else if (!strcasecmp(cmd, "NoAudio")) {
4533 audio_id = CODEC_ID_NONE;
4534 } else if (!strcasecmp(cmd, "ACL")) {
4535 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4536 } else if (!strcasecmp(cmd, "DynamicACL")) {
4538 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4540 } else if (!strcasecmp(cmd, "RTSPOption")) {
4541 get_arg(arg, sizeof(arg), &p);
4543 av_freep(&stream->rtsp_option);
4544 stream->rtsp_option = av_strdup(arg);
4546 } else if (!strcasecmp(cmd, "MulticastAddress")) {
4547 get_arg(arg, sizeof(arg), &p);
4549 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4550 ERROR("Invalid host/IP address: %s\n", arg);
4552 stream->is_multicast = 1;
4553 stream->loop = 1; /* default is looping */
4555 } else if (!strcasecmp(cmd, "MulticastPort")) {
4556 get_arg(arg, sizeof(arg), &p);
4558 stream->multicast_port = atoi(arg);
4559 } else if (!strcasecmp(cmd, "MulticastTTL")) {
4560 get_arg(arg, sizeof(arg), &p);
4562 stream->multicast_ttl = atoi(arg);
4563 } else if (!strcasecmp(cmd, "NoLoop")) {
4566 } else if (!strcasecmp(cmd, "</Stream>")) {
4568 ERROR("No corresponding <Stream> for </Stream>\n");
4570 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4571 if (audio_id != CODEC_ID_NONE) {
4572 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4573 audio_enc.codec_id = audio_id;
4574 add_codec(stream, &audio_enc);
4576 if (video_id != CODEC_ID_NONE) {
4577 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4578 video_enc.codec_id = video_id;
4579 add_codec(stream, &video_enc);
4584 } else if (!strcasecmp(cmd, "<Redirect")) {
4585 /*********************************************/
4587 if (stream || feed || redirect) {
4588 ERROR("Already in a tag\n");
4590 redirect = av_mallocz(sizeof(FFStream));
4591 *last_stream = redirect;
4592 last_stream = &redirect->next;
4594 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4595 q = strrchr(redirect->filename, '>');
4598 redirect->stream_type = STREAM_TYPE_REDIRECT;
4600 } else if (!strcasecmp(cmd, "URL")) {
4602 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4603 } else if (!strcasecmp(cmd, "</Redirect>")) {
4605 ERROR("No corresponding <Redirect> for </Redirect>\n");
4607 if (!redirect->feed_filename[0]) {
4608 ERROR("No URL found for <Redirect>\n");
4612 } else if (!strcasecmp(cmd, "LoadModule")) {
4613 get_arg(arg, sizeof(arg), &p);
4617 ERROR("Module support not compiled into this version: '%s'\n", arg);
4620 ERROR("Incorrect keyword: '%s'\n", cmd);
4632 static void handle_child_exit(int sig)
4637 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4640 for (feed = first_feed; feed; feed = feed->next) {
4641 if (feed->pid == pid) {
4642 int uptime = time(0) - feed->pid_start;
4645 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4648 /* Turn off any more restarts */
4649 feed->child_argv = 0;
4654 need_to_start_children = 1;
4657 static void opt_debug(void)
4660 ffserver_daemon = 0;
4661 logfilename[0] = '-';
4664 static void show_help(void)
4666 printf("usage: ffserver [options]\n"
4667 "Hyper fast multi format Audio/Video streaming server\n");
4669 show_help_options(options, "Main options:\n", 0, 0);
4672 static const OptionDef options[] = {
4673 #include "cmdutils_common_opts.h"
4674 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4675 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4676 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4680 int main(int argc, char **argv)
4682 struct sigaction sigact;
4688 my_program_name = argv[0];
4689 my_program_dir = getcwd(0, 0);
4690 ffserver_daemon = 1;
4692 parse_options(argc, argv, options, NULL);
4694 unsetenv("http_proxy"); /* Kill the http_proxy */
4696 av_lfg_init(&random_state, av_get_random_seed());
4698 memset(&sigact, 0, sizeof(sigact));
4699 sigact.sa_handler = handle_child_exit;
4700 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4701 sigaction(SIGCHLD, &sigact, 0);
4703 if (parse_ffconfig(config_filename) < 0) {
4704 fprintf(stderr, "Incorrect config file - exiting.\n");
4708 /* open log file if needed */
4709 if (logfilename[0] != '\0') {
4710 if (!strcmp(logfilename, "-"))
4713 logfile = fopen(logfilename, "a");
4714 av_log_set_callback(http_av_log);
4717 build_file_streams();
4719 build_feed_streams();
4721 compute_bandwidth();
4723 /* put the process in background and detach it from its TTY */
4724 if (ffserver_daemon) {
4731 } else if (pid > 0) {
4738 open("/dev/null", O_RDWR);
4739 if (strcmp(logfilename, "-") != 0) {
4749 signal(SIGPIPE, SIG_IGN);
4751 if (ffserver_daemon)
4754 if (http_server() < 0) {
4755 http_log("Could not start server\n");