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(AVStream *) * c->stream->nb_streams);
2234 for(i=0;i<c->stream->nb_streams;i++) {
2236 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2237 /* if file or feed, then just take streams from FFStream struct */
2238 if (!c->stream->feed ||
2239 c->stream->feed == c->stream)
2240 src = c->stream->streams[i];
2242 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2244 *(c->fmt_ctx.streams[i]) = *src;
2245 c->fmt_ctx.streams[i]->priv_data = 0;
2246 c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2247 AVStream, not in codec */
2249 /* set output format parameters */
2250 c->fmt_ctx.oformat = c->stream->fmt;
2251 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2253 c->got_key_frame = 0;
2255 /* prepare header and save header data in a stream */
2256 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2257 /* XXX: potential leak */
2260 c->fmt_ctx.pb->seekable = 0;
2263 * HACK to avoid mpeg ps muxer to spit many underflow errors
2264 * Default value from FFmpeg
2265 * Try to set it use configuration option
2267 c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
2268 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2270 av_set_parameters(&c->fmt_ctx, NULL);
2271 if (av_write_header(&c->fmt_ctx) < 0) {
2272 http_log("Error writing output header\n");
2275 av_metadata_free(&c->fmt_ctx.metadata);
2277 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2278 c->buffer_ptr = c->pb_buffer;
2279 c->buffer_end = c->pb_buffer + len;
2281 c->state = HTTPSTATE_SEND_DATA;
2282 c->last_packet_sent = 0;
2284 case HTTPSTATE_SEND_DATA:
2285 /* find a new packet */
2286 /* read a packet from the input stream */
2287 if (c->stream->feed)
2288 ffm_set_write_index(c->fmt_in,
2289 c->stream->feed->feed_write_index,
2290 c->stream->feed->feed_size);
2292 if (c->stream->max_time &&
2293 c->stream->max_time + c->start_time - cur_time < 0)
2294 /* We have timed out */
2295 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2299 ret = av_read_frame(c->fmt_in, &pkt);
2301 if (c->stream->feed) {
2302 /* if coming from feed, it means we reached the end of the
2303 ffm file, so must wait for more data */
2304 c->state = HTTPSTATE_WAIT_FEED;
2305 return 1; /* state changed */
2306 } else if (ret == AVERROR(EAGAIN)) {
2307 /* input not ready, come back later */
2310 if (c->stream->loop) {
2311 av_close_input_file(c->fmt_in);
2313 if (open_input_stream(c, "") < 0)
2318 /* must send trailer now because eof or error */
2319 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2323 int source_index = pkt.stream_index;
2324 /* update first pts if needed */
2325 if (c->first_pts == AV_NOPTS_VALUE) {
2326 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2327 c->start_time = cur_time;
2329 /* send it to the appropriate stream */
2330 if (c->stream->feed) {
2331 /* if coming from a feed, select the right stream */
2332 if (c->switch_pending) {
2333 c->switch_pending = 0;
2334 for(i=0;i<c->stream->nb_streams;i++) {
2335 if (c->switch_feed_streams[i] == pkt.stream_index)
2336 if (pkt.flags & AV_PKT_FLAG_KEY)
2337 c->switch_feed_streams[i] = -1;
2338 if (c->switch_feed_streams[i] >= 0)
2339 c->switch_pending = 1;
2342 for(i=0;i<c->stream->nb_streams;i++) {
2343 if (c->stream->feed_streams[i] == pkt.stream_index) {
2344 AVStream *st = c->fmt_in->streams[source_index];
2345 pkt.stream_index = i;
2346 if (pkt.flags & AV_PKT_FLAG_KEY &&
2347 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2348 c->stream->nb_streams == 1))
2349 c->got_key_frame = 1;
2350 if (!c->stream->send_on_key || c->got_key_frame)
2355 AVCodecContext *codec;
2356 AVStream *ist, *ost;
2358 ist = c->fmt_in->streams[source_index];
2359 /* specific handling for RTP: we use several
2360 output stream (one for each RTP
2361 connection). XXX: need more abstract handling */
2362 if (c->is_packetized) {
2363 /* compute send time and duration */
2364 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2365 c->cur_pts -= c->first_pts;
2366 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2367 /* find RTP context */
2368 c->packet_stream_index = pkt.stream_index;
2369 ctx = c->rtp_ctx[c->packet_stream_index];
2371 av_free_packet(&pkt);
2374 codec = ctx->streams[0]->codec;
2375 /* only one stream per RTP connection */
2376 pkt.stream_index = 0;
2380 codec = ctx->streams[pkt.stream_index]->codec;
2383 if (c->is_packetized) {
2384 int max_packet_size;
2385 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2386 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2388 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2389 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2391 ret = avio_open_dyn_buf(&ctx->pb);
2394 /* XXX: potential leak */
2397 ost = ctx->streams[pkt.stream_index];
2399 ctx->pb->seekable = 0;
2400 if (pkt.dts != AV_NOPTS_VALUE)
2401 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2402 if (pkt.pts != AV_NOPTS_VALUE)
2403 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2404 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2405 if (av_write_frame(ctx, &pkt) < 0) {
2406 http_log("Error writing frame to output\n");
2407 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2410 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2411 c->cur_frame_bytes = len;
2412 c->buffer_ptr = c->pb_buffer;
2413 c->buffer_end = c->pb_buffer + len;
2415 codec->frame_number++;
2417 av_free_packet(&pkt);
2421 av_free_packet(&pkt);
2426 case HTTPSTATE_SEND_DATA_TRAILER:
2427 /* last packet test ? */
2428 if (c->last_packet_sent || c->is_packetized)
2431 /* prepare header */
2432 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2433 /* XXX: potential leak */
2436 c->fmt_ctx.pb->seekable = 0;
2437 av_write_trailer(ctx);
2438 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2439 c->buffer_ptr = c->pb_buffer;
2440 c->buffer_end = c->pb_buffer + len;
2442 c->last_packet_sent = 1;
2448 /* should convert the format at the same time */
2449 /* send data starting at c->buffer_ptr to the output connection
2450 (either UDP or TCP connection) */
2451 static int http_send_data(HTTPContext *c)
2456 if (c->buffer_ptr >= c->buffer_end) {
2457 ret = http_prepare_data(c);
2461 /* state change requested */
2464 if (c->is_packetized) {
2465 /* RTP data output */
2466 len = c->buffer_end - c->buffer_ptr;
2468 /* fail safe - should never happen */
2470 c->buffer_ptr = c->buffer_end;
2473 len = (c->buffer_ptr[0] << 24) |
2474 (c->buffer_ptr[1] << 16) |
2475 (c->buffer_ptr[2] << 8) |
2477 if (len > (c->buffer_end - c->buffer_ptr))
2479 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2480 /* nothing to send yet: we can wait */
2484 c->data_count += len;
2485 update_datarate(&c->datarate, c->data_count);
2487 c->stream->bytes_served += len;
2489 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2490 /* RTP packets are sent inside the RTSP TCP connection */
2492 int interleaved_index, size;
2494 HTTPContext *rtsp_c;
2497 /* if no RTSP connection left, error */
2500 /* if already sending something, then wait. */
2501 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2503 if (avio_open_dyn_buf(&pb) < 0)
2505 interleaved_index = c->packet_stream_index * 2;
2506 /* RTCP packets are sent at odd indexes */
2507 if (c->buffer_ptr[1] == 200)
2508 interleaved_index++;
2509 /* write RTSP TCP header */
2511 header[1] = interleaved_index;
2512 header[2] = len >> 8;
2514 avio_write(pb, header, 4);
2515 /* write RTP packet data */
2517 avio_write(pb, c->buffer_ptr, len);
2518 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2519 /* prepare asynchronous TCP sending */
2520 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2521 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2522 c->buffer_ptr += len;
2524 /* send everything we can NOW */
2525 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2526 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2528 rtsp_c->packet_buffer_ptr += len;
2529 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2530 /* if we could not send all the data, we will
2531 send it later, so a new state is needed to
2532 "lock" the RTSP TCP connection */
2533 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2536 /* all data has been sent */
2537 av_freep(&c->packet_buffer);
2539 /* send RTP packet directly in UDP */
2541 url_write(c->rtp_handles[c->packet_stream_index],
2542 c->buffer_ptr, len);
2543 c->buffer_ptr += len;
2544 /* here we continue as we can send several packets per 10 ms slot */
2547 /* TCP data output */
2548 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2550 if (ff_neterrno() != AVERROR(EAGAIN) &&
2551 ff_neterrno() != AVERROR(EINTR))
2552 /* error : close connection */
2557 c->buffer_ptr += len;
2559 c->data_count += len;
2560 update_datarate(&c->datarate, c->data_count);
2562 c->stream->bytes_served += len;
2570 static int http_start_receive_data(HTTPContext *c)
2574 if (c->stream->feed_opened)
2577 /* Don't permit writing to this one */
2578 if (c->stream->readonly)
2582 fd = open(c->stream->feed_filename, O_RDWR);
2584 http_log("Error opening feeder file: %s\n", strerror(errno));
2589 if (c->stream->truncate) {
2590 /* truncate feed file */
2591 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2592 ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2593 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2595 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2596 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2601 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2602 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2603 lseek(fd, 0, SEEK_SET);
2605 /* init buffer input */
2606 c->buffer_ptr = c->buffer;
2607 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2608 c->stream->feed_opened = 1;
2609 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2613 static int http_receive_data(HTTPContext *c)
2616 int len, loop_run = 0;
2618 while (c->chunked_encoding && !c->chunk_size &&
2619 c->buffer_end > c->buffer_ptr) {
2620 /* read chunk header, if present */
2621 len = recv(c->fd, c->buffer_ptr, 1, 0);
2624 if (ff_neterrno() != AVERROR(EAGAIN) &&
2625 ff_neterrno() != AVERROR(EINTR))
2626 /* error : close connection */
2629 } else if (len == 0) {
2630 /* end of connection : close it */
2632 } else if (c->buffer_ptr - c->buffer >= 2 &&
2633 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2634 c->chunk_size = strtol(c->buffer, 0, 16);
2635 if (c->chunk_size == 0) // end of stream
2637 c->buffer_ptr = c->buffer;
2639 } else if (++loop_run > 10) {
2640 /* no chunk header, abort */
2647 if (c->buffer_end > c->buffer_ptr) {
2648 len = recv(c->fd, c->buffer_ptr,
2649 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2651 if (ff_neterrno() != AVERROR(EAGAIN) &&
2652 ff_neterrno() != AVERROR(EINTR))
2653 /* error : close connection */
2655 } else if (len == 0)
2656 /* end of connection : close it */
2659 c->chunk_size -= len;
2660 c->buffer_ptr += len;
2661 c->data_count += len;
2662 update_datarate(&c->datarate, c->data_count);
2666 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2667 if (c->buffer[0] != 'f' ||
2668 c->buffer[1] != 'm') {
2669 http_log("Feed stream has become desynchronized -- disconnecting\n");
2674 if (c->buffer_ptr >= c->buffer_end) {
2675 FFStream *feed = c->stream;
2676 /* a packet has been received : write it in the store, except
2678 if (c->data_count > FFM_PACKET_SIZE) {
2680 // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2681 /* XXX: use llseek or url_seek */
2682 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2683 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2684 http_log("Error writing to feed file: %s\n", strerror(errno));
2688 feed->feed_write_index += FFM_PACKET_SIZE;
2689 /* update file size */
2690 if (feed->feed_write_index > c->stream->feed_size)
2691 feed->feed_size = feed->feed_write_index;
2693 /* handle wrap around if max file size reached */
2694 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2695 feed->feed_write_index = FFM_PACKET_SIZE;
2698 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2699 http_log("Error writing index to feed file: %s\n", strerror(errno));
2703 /* wake up any waiting connections */
2704 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2705 if (c1->state == HTTPSTATE_WAIT_FEED &&
2706 c1->stream->feed == c->stream->feed)
2707 c1->state = HTTPSTATE_SEND_DATA;
2710 /* We have a header in our hands that contains useful data */
2711 AVFormatContext *s = NULL;
2713 AVInputFormat *fmt_in;
2716 /* use feed output format name to find corresponding input format */
2717 fmt_in = av_find_input_format(feed->fmt->name);
2721 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2722 0, NULL, NULL, NULL, NULL);
2725 if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2730 /* Now we have the actual streams */
2731 if (s->nb_streams != feed->nb_streams) {
2732 av_close_input_stream(s);
2734 http_log("Feed '%s' stream number does not match registered feed\n",
2735 c->stream->feed_filename);
2739 for (i = 0; i < s->nb_streams; i++) {
2740 AVStream *fst = feed->streams[i];
2741 AVStream *st = s->streams[i];
2742 avcodec_copy_context(fst->codec, st->codec);
2745 av_close_input_stream(s);
2748 c->buffer_ptr = c->buffer;
2753 c->stream->feed_opened = 0;
2755 /* wake up any waiting connections to stop waiting for feed */
2756 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2757 if (c1->state == HTTPSTATE_WAIT_FEED &&
2758 c1->stream->feed == c->stream->feed)
2759 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2764 /********************************************************************/
2767 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2774 switch(error_number) {
2775 case RTSP_STATUS_OK:
2778 case RTSP_STATUS_METHOD:
2779 str = "Method Not Allowed";
2781 case RTSP_STATUS_BANDWIDTH:
2782 str = "Not Enough Bandwidth";
2784 case RTSP_STATUS_SESSION:
2785 str = "Session Not Found";
2787 case RTSP_STATUS_STATE:
2788 str = "Method Not Valid in This State";
2790 case RTSP_STATUS_AGGREGATE:
2791 str = "Aggregate operation not allowed";
2793 case RTSP_STATUS_ONLY_AGGREGATE:
2794 str = "Only aggregate operation allowed";
2796 case RTSP_STATUS_TRANSPORT:
2797 str = "Unsupported transport";
2799 case RTSP_STATUS_INTERNAL:
2800 str = "Internal Server Error";
2802 case RTSP_STATUS_SERVICE:
2803 str = "Service Unavailable";
2805 case RTSP_STATUS_VERSION:
2806 str = "RTSP Version not supported";
2809 str = "Unknown Error";
2813 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2814 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2816 /* output GMT time */
2819 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2820 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2823 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2825 rtsp_reply_header(c, error_number);
2826 avio_printf(c->pb, "\r\n");
2829 static int rtsp_parse_request(HTTPContext *c)
2831 const char *p, *p1, *p2;
2837 RTSPMessageHeader header1, *header = &header1;
2839 c->buffer_ptr[0] = '\0';
2842 get_word(cmd, sizeof(cmd), &p);
2843 get_word(url, sizeof(url), &p);
2844 get_word(protocol, sizeof(protocol), &p);
2846 av_strlcpy(c->method, cmd, sizeof(c->method));
2847 av_strlcpy(c->url, url, sizeof(c->url));
2848 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2850 if (avio_open_dyn_buf(&c->pb) < 0) {
2851 /* XXX: cannot do more */
2852 c->pb = NULL; /* safety */
2856 /* check version name */
2857 if (strcmp(protocol, "RTSP/1.0") != 0) {
2858 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2862 /* parse each header line */
2863 memset(header, 0, sizeof(*header));
2864 /* skip to next line */
2865 while (*p != '\n' && *p != '\0')
2869 while (*p != '\0') {
2870 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2874 if (p2 > p && p2[-1] == '\r')
2876 /* skip empty line */
2880 if (len > sizeof(line) - 1)
2881 len = sizeof(line) - 1;
2882 memcpy(line, p, len);
2884 ff_rtsp_parse_line(header, line, NULL, NULL);
2888 /* handle sequence number */
2889 c->seq = header->seq;
2891 if (!strcmp(cmd, "DESCRIBE"))
2892 rtsp_cmd_describe(c, url);
2893 else if (!strcmp(cmd, "OPTIONS"))
2894 rtsp_cmd_options(c, url);
2895 else if (!strcmp(cmd, "SETUP"))
2896 rtsp_cmd_setup(c, url, header);
2897 else if (!strcmp(cmd, "PLAY"))
2898 rtsp_cmd_play(c, url, header);
2899 else if (!strcmp(cmd, "PAUSE"))
2900 rtsp_cmd_pause(c, url, header);
2901 else if (!strcmp(cmd, "TEARDOWN"))
2902 rtsp_cmd_teardown(c, url, header);
2904 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2907 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2908 c->pb = NULL; /* safety */
2910 /* XXX: cannot do more */
2913 c->buffer_ptr = c->pb_buffer;
2914 c->buffer_end = c->pb_buffer + len;
2915 c->state = RTSPSTATE_SEND_REPLY;
2919 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2920 struct in_addr my_ip)
2922 AVFormatContext *avc;
2923 AVStream *avs = NULL;
2926 avc = avformat_alloc_context();
2930 av_metadata_set2(&avc->metadata, "title",
2931 stream->title[0] ? stream->title : "No Title", 0);
2932 avc->nb_streams = stream->nb_streams;
2933 if (stream->is_multicast) {
2934 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2935 inet_ntoa(stream->multicast_ip),
2936 stream->multicast_port, stream->multicast_ttl);
2938 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2941 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2942 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2944 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2945 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2948 for(i = 0; i < stream->nb_streams; i++) {
2949 avc->streams[i] = &avs[i];
2950 avc->streams[i]->codec = stream->streams[i]->codec;
2952 *pbuffer = av_mallocz(2048);
2953 av_sdp_create(&avc, 1, *pbuffer, 2048);
2956 av_free(avc->streams);
2957 av_metadata_free(&avc->metadata);
2961 return strlen(*pbuffer);
2964 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2966 // rtsp_reply_header(c, RTSP_STATUS_OK);
2967 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2968 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2969 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2970 avio_printf(c->pb, "\r\n");
2973 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2979 int content_length, len;
2980 struct sockaddr_in my_addr;
2982 /* find which url is asked */
2983 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2988 for(stream = first_stream; stream != NULL; stream = stream->next) {
2989 if (!stream->is_feed &&
2990 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
2991 !strcmp(path, stream->filename)) {
2995 /* no stream found */
2996 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3000 /* prepare the media description in sdp format */
3002 /* get the host IP */
3003 len = sizeof(my_addr);
3004 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3005 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3006 if (content_length < 0) {
3007 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3010 rtsp_reply_header(c, RTSP_STATUS_OK);
3011 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3012 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3013 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3014 avio_printf(c->pb, "\r\n");
3015 avio_write(c->pb, content, content_length);
3019 static HTTPContext *find_rtp_session(const char *session_id)
3023 if (session_id[0] == '\0')
3026 for(c = first_http_ctx; c != NULL; c = c->next) {
3027 if (!strcmp(c->session_id, session_id))
3033 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3035 RTSPTransportField *th;
3038 for(i=0;i<h->nb_transports;i++) {
3039 th = &h->transports[i];
3040 if (th->lower_transport == lower_transport)
3046 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3047 RTSPMessageHeader *h)
3050 int stream_index, rtp_port, rtcp_port;
3055 RTSPTransportField *th;
3056 struct sockaddr_in dest_addr;
3057 RTSPActionServerSetup setup;
3059 /* find which url is asked */
3060 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3065 /* now check each stream */
3066 for(stream = first_stream; stream != NULL; stream = stream->next) {
3067 if (!stream->is_feed &&
3068 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3069 /* accept aggregate filenames only if single stream */
3070 if (!strcmp(path, stream->filename)) {
3071 if (stream->nb_streams != 1) {
3072 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3079 for(stream_index = 0; stream_index < stream->nb_streams;
3081 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3082 stream->filename, stream_index);
3083 if (!strcmp(path, buf))
3088 /* no stream found */
3089 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3093 /* generate session id if needed */
3094 if (h->session_id[0] == '\0')
3095 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3096 av_lfg_get(&random_state), av_lfg_get(&random_state));
3098 /* find rtp session, and create it if none found */
3099 rtp_c = find_rtp_session(h->session_id);
3101 /* always prefer UDP */
3102 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3104 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3106 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3111 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3112 th->lower_transport);
3114 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3118 /* open input stream */
3119 if (open_input_stream(rtp_c, "") < 0) {
3120 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3125 /* test if stream is OK (test needed because several SETUP needs
3126 to be done for a given file) */
3127 if (rtp_c->stream != stream) {
3128 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3132 /* test if stream is already set up */
3133 if (rtp_c->rtp_ctx[stream_index]) {
3134 rtsp_reply_error(c, RTSP_STATUS_STATE);
3138 /* check transport */
3139 th = find_transport(h, rtp_c->rtp_protocol);
3140 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3141 th->client_port_min <= 0)) {
3142 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3146 /* setup default options */
3147 setup.transport_option[0] = '\0';
3148 dest_addr = rtp_c->from_addr;
3149 dest_addr.sin_port = htons(th->client_port_min);
3152 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3153 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3157 /* now everything is OK, so we can send the connection parameters */
3158 rtsp_reply_header(c, RTSP_STATUS_OK);
3160 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3162 switch(rtp_c->rtp_protocol) {
3163 case RTSP_LOWER_TRANSPORT_UDP:
3164 rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3165 rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3166 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3167 "client_port=%d-%d;server_port=%d-%d",
3168 th->client_port_min, th->client_port_max,
3169 rtp_port, rtcp_port);
3171 case RTSP_LOWER_TRANSPORT_TCP:
3172 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3173 stream_index * 2, stream_index * 2 + 1);
3178 if (setup.transport_option[0] != '\0')
3179 avio_printf(c->pb, ";%s", setup.transport_option);
3180 avio_printf(c->pb, "\r\n");
3183 avio_printf(c->pb, "\r\n");
3187 /* find an rtp connection by using the session ID. Check consistency
3189 static HTTPContext *find_rtp_session_with_url(const char *url,
3190 const char *session_id)
3198 rtp_c = find_rtp_session(session_id);
3202 /* find which url is asked */
3203 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3207 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3208 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3209 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3210 rtp_c->stream->filename, s);
3211 if(!strncmp(path, buf, sizeof(buf))) {
3212 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3217 if (len > 0 && path[len - 1] == '/' &&
3218 !strncmp(path, rtp_c->stream->filename, len - 1))
3223 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3227 rtp_c = find_rtp_session_with_url(url, h->session_id);
3229 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3233 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3234 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3235 rtp_c->state != HTTPSTATE_READY) {
3236 rtsp_reply_error(c, RTSP_STATUS_STATE);
3240 rtp_c->state = HTTPSTATE_SEND_DATA;
3242 /* now everything is OK, so we can send the connection parameters */
3243 rtsp_reply_header(c, RTSP_STATUS_OK);
3245 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3246 avio_printf(c->pb, "\r\n");
3249 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3253 rtp_c = find_rtp_session_with_url(url, h->session_id);
3255 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3259 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3260 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3261 rtsp_reply_error(c, RTSP_STATUS_STATE);
3265 rtp_c->state = HTTPSTATE_READY;
3266 rtp_c->first_pts = AV_NOPTS_VALUE;
3267 /* now everything is OK, so we can send the connection parameters */
3268 rtsp_reply_header(c, RTSP_STATUS_OK);
3270 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3271 avio_printf(c->pb, "\r\n");
3274 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3278 rtp_c = find_rtp_session_with_url(url, h->session_id);
3280 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3284 /* now everything is OK, so we can send the connection parameters */
3285 rtsp_reply_header(c, RTSP_STATUS_OK);
3287 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3288 avio_printf(c->pb, "\r\n");
3290 /* abort the session */
3291 close_connection(rtp_c);
3295 /********************************************************************/
3298 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3299 FFStream *stream, const char *session_id,
3300 enum RTSPLowerTransport rtp_protocol)
3302 HTTPContext *c = NULL;
3303 const char *proto_str;
3305 /* XXX: should output a warning page when coming
3306 close to the connection limit */
3307 if (nb_connections >= nb_max_connections)
3310 /* add a new connection */
3311 c = av_mallocz(sizeof(HTTPContext));
3316 c->poll_entry = NULL;
3317 c->from_addr = *from_addr;
3318 c->buffer_size = IOBUFFER_INIT_SIZE;
3319 c->buffer = av_malloc(c->buffer_size);
3324 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3325 c->state = HTTPSTATE_READY;
3326 c->is_packetized = 1;
3327 c->rtp_protocol = rtp_protocol;
3329 /* protocol is shown in statistics */
3330 switch(c->rtp_protocol) {
3331 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3332 proto_str = "MCAST";
3334 case RTSP_LOWER_TRANSPORT_UDP:
3337 case RTSP_LOWER_TRANSPORT_TCP:
3344 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3345 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3347 current_bandwidth += stream->bandwidth;
3349 c->next = first_http_ctx;
3361 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3362 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3364 static int rtp_new_av_stream(HTTPContext *c,
3365 int stream_index, struct sockaddr_in *dest_addr,
3366 HTTPContext *rtsp_c)
3368 AVFormatContext *ctx;
3371 URLContext *h = NULL;
3373 int max_packet_size;
3375 /* now we can open the relevant output stream */
3376 ctx = avformat_alloc_context();
3379 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3381 st = av_mallocz(sizeof(AVStream));
3384 ctx->nb_streams = 1;
3385 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3388 ctx->streams[0] = st;
3390 if (!c->stream->feed ||
3391 c->stream->feed == c->stream)
3392 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3395 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3397 st->priv_data = NULL;
3399 /* build destination RTP address */
3400 ipaddr = inet_ntoa(dest_addr->sin_addr);
3402 switch(c->rtp_protocol) {
3403 case RTSP_LOWER_TRANSPORT_UDP:
3404 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3407 /* XXX: also pass as parameter to function ? */
3408 if (c->stream->is_multicast) {
3410 ttl = c->stream->multicast_ttl;
3413 snprintf(ctx->filename, sizeof(ctx->filename),
3414 "rtp://%s:%d?multicast=1&ttl=%d",
3415 ipaddr, ntohs(dest_addr->sin_port), ttl);
3417 snprintf(ctx->filename, sizeof(ctx->filename),
3418 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3421 if (url_open(&h, ctx->filename, AVIO_FLAG_WRITE) < 0)
3423 c->rtp_handles[stream_index] = h;
3424 max_packet_size = url_get_max_packet_size(h);
3426 case RTSP_LOWER_TRANSPORT_TCP:
3429 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3435 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3436 ipaddr, ntohs(dest_addr->sin_port),
3437 c->stream->filename, stream_index, c->protocol);
3439 /* normally, no packets should be output here, but the packet size may be checked */
3440 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3441 /* XXX: close stream */
3444 av_set_parameters(ctx, NULL);
3445 if (av_write_header(ctx) < 0) {
3452 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3455 c->rtp_ctx[stream_index] = ctx;
3459 /********************************************************************/
3460 /* ffserver initialization */
3462 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3466 fst = av_mallocz(sizeof(AVStream));
3470 fst->codec= avcodec_alloc_context();
3471 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3472 if (codec->extradata_size) {
3473 fst->codec->extradata = av_malloc(codec->extradata_size);
3474 memcpy(fst->codec->extradata, codec->extradata,
3475 codec->extradata_size);
3478 /* live streams must use the actual feed's codec since it may be
3479 * updated later to carry extradata needed by the streams.
3483 fst->priv_data = av_mallocz(sizeof(FeedData));
3484 fst->index = stream->nb_streams;
3485 av_set_pts_info(fst, 33, 1, 90000);
3486 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3487 stream->streams[stream->nb_streams++] = fst;
3491 /* return the stream number in the feed */
3492 static int add_av_stream(FFStream *feed, AVStream *st)
3495 AVCodecContext *av, *av1;
3499 for(i=0;i<feed->nb_streams;i++) {
3500 st = feed->streams[i];
3502 if (av1->codec_id == av->codec_id &&
3503 av1->codec_type == av->codec_type &&
3504 av1->bit_rate == av->bit_rate) {
3506 switch(av->codec_type) {
3507 case AVMEDIA_TYPE_AUDIO:
3508 if (av1->channels == av->channels &&
3509 av1->sample_rate == av->sample_rate)
3512 case AVMEDIA_TYPE_VIDEO:
3513 if (av1->width == av->width &&
3514 av1->height == av->height &&
3515 av1->time_base.den == av->time_base.den &&
3516 av1->time_base.num == av->time_base.num &&
3517 av1->gop_size == av->gop_size)
3526 fst = add_av_stream1(feed, av, 0);
3529 return feed->nb_streams - 1;
3534 static void remove_stream(FFStream *stream)
3538 while (*ps != NULL) {
3546 /* specific mpeg4 handling : we extract the raw parameters */
3547 static void extract_mpeg4_header(AVFormatContext *infile)
3549 int mpeg4_count, i, size;
3555 for(i=0;i<infile->nb_streams;i++) {
3556 st = infile->streams[i];
3557 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3558 st->codec->extradata_size == 0) {
3565 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3566 while (mpeg4_count > 0) {
3567 if (av_read_packet(infile, &pkt) < 0)
3569 st = infile->streams[pkt.stream_index];
3570 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3571 st->codec->extradata_size == 0) {
3572 av_freep(&st->codec->extradata);
3573 /* fill extradata with the header */
3574 /* XXX: we make hard suppositions here ! */
3576 while (p < pkt.data + pkt.size - 4) {
3577 /* stop when vop header is found */
3578 if (p[0] == 0x00 && p[1] == 0x00 &&
3579 p[2] == 0x01 && p[3] == 0xb6) {
3580 size = p - pkt.data;
3581 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3582 st->codec->extradata = av_malloc(size);
3583 st->codec->extradata_size = size;
3584 memcpy(st->codec->extradata, pkt.data, size);
3591 av_free_packet(&pkt);
3595 /* compute the needed AVStream for each file */
3596 static void build_file_streams(void)
3598 FFStream *stream, *stream_next;
3599 AVFormatContext *infile;
3602 /* gather all streams */
3603 for(stream = first_stream; stream != NULL; stream = stream_next) {
3604 stream_next = stream->next;
3605 if (stream->stream_type == STREAM_TYPE_LIVE &&
3607 /* the stream comes from a file */
3608 /* try to open the file */
3610 stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3611 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3612 /* specific case : if transport stream output to RTP,
3613 we use a raw transport stream reader */
3614 stream->ap_in->mpeg2ts_raw = 1;
3615 stream->ap_in->mpeg2ts_compute_pcr = 1;
3618 http_log("Opening file '%s'\n", stream->feed_filename);
3619 if ((ret = av_open_input_file(&infile, stream->feed_filename,
3620 stream->ifmt, 0, stream->ap_in)) < 0) {
3621 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3622 /* remove stream (no need to spend more time on it) */
3624 remove_stream(stream);
3626 /* find all the AVStreams inside and reference them in
3628 if (av_find_stream_info(infile) < 0) {
3629 http_log("Could not find codec parameters from '%s'\n",
3630 stream->feed_filename);
3631 av_close_input_file(infile);
3634 extract_mpeg4_header(infile);
3636 for(i=0;i<infile->nb_streams;i++)
3637 add_av_stream1(stream, infile->streams[i]->codec, 1);
3639 av_close_input_file(infile);
3645 /* compute the needed AVStream for each feed */
3646 static void build_feed_streams(void)
3648 FFStream *stream, *feed;
3651 /* gather all streams */
3652 for(stream = first_stream; stream != NULL; stream = stream->next) {
3653 feed = stream->feed;
3655 if (!stream->is_feed) {
3656 /* we handle a stream coming from a feed */
3657 for(i=0;i<stream->nb_streams;i++)
3658 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3663 /* gather all streams */
3664 for(stream = first_stream; stream != NULL; stream = stream->next) {
3665 feed = stream->feed;
3667 if (stream->is_feed) {
3668 for(i=0;i<stream->nb_streams;i++)
3669 stream->feed_streams[i] = i;
3674 /* create feed files if needed */
3675 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3678 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3679 /* See if it matches */
3683 if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3684 /* Now see if it matches */
3685 if (s->nb_streams == feed->nb_streams) {
3687 for(i=0;i<s->nb_streams;i++) {
3689 sf = feed->streams[i];
3692 if (sf->index != ss->index ||
3694 http_log("Index & Id do not match for stream %d (%s)\n",
3695 i, feed->feed_filename);
3698 AVCodecContext *ccf, *ccs;
3702 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3704 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3705 http_log("Codecs do not match for stream %d\n", i);
3707 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3708 http_log("Codec bitrates do not match for stream %d\n", i);
3710 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3711 if (CHECK_CODEC(time_base.den) ||
3712 CHECK_CODEC(time_base.num) ||
3713 CHECK_CODEC(width) ||
3714 CHECK_CODEC(height)) {
3715 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3718 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3719 if (CHECK_CODEC(sample_rate) ||
3720 CHECK_CODEC(channels) ||
3721 CHECK_CODEC(frame_size)) {
3722 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3726 http_log("Unknown codec type\n");
3734 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3735 feed->feed_filename, s->nb_streams, feed->nb_streams);
3737 av_close_input_file(s);
3739 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3740 feed->feed_filename);
3743 if (feed->readonly) {
3744 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3745 feed->feed_filename);
3748 unlink(feed->feed_filename);
3751 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3752 AVFormatContext s1 = {0}, *s = &s1;
3754 if (feed->readonly) {
3755 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3756 feed->feed_filename);
3760 /* only write the header of the ffm file */
3761 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3762 http_log("Could not open output feed file '%s'\n",
3763 feed->feed_filename);
3766 s->oformat = feed->fmt;
3767 s->nb_streams = feed->nb_streams;
3768 s->streams = feed->streams;
3769 av_set_parameters(s, NULL);
3770 if (av_write_header(s) < 0) {
3771 http_log("Container doesn't supports the required parameters\n");
3774 /* XXX: need better api */
3775 av_freep(&s->priv_data);
3778 /* get feed size and write index */
3779 fd = open(feed->feed_filename, O_RDONLY);
3781 http_log("Could not open output feed file '%s'\n",
3782 feed->feed_filename);
3786 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3787 feed->feed_size = lseek(fd, 0, SEEK_END);
3788 /* ensure that we do not wrap before the end of file */
3789 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3790 feed->feed_max_size = feed->feed_size;
3796 /* compute the bandwidth used by each stream */
3797 static void compute_bandwidth(void)
3803 for(stream = first_stream; stream != NULL; stream = stream->next) {
3805 for(i=0;i<stream->nb_streams;i++) {
3806 AVStream *st = stream->streams[i];
3807 switch(st->codec->codec_type) {
3808 case AVMEDIA_TYPE_AUDIO:
3809 case AVMEDIA_TYPE_VIDEO:
3810 bandwidth += st->codec->bit_rate;
3816 stream->bandwidth = (bandwidth + 999) / 1000;
3820 /* add a codec and set the default parameters */
3821 static void add_codec(FFStream *stream, AVCodecContext *av)
3825 /* compute default parameters */
3826 switch(av->codec_type) {
3827 case AVMEDIA_TYPE_AUDIO:
3828 if (av->bit_rate == 0)
3829 av->bit_rate = 64000;
3830 if (av->sample_rate == 0)
3831 av->sample_rate = 22050;
3832 if (av->channels == 0)
3835 case AVMEDIA_TYPE_VIDEO:
3836 if (av->bit_rate == 0)
3837 av->bit_rate = 64000;
3838 if (av->time_base.num == 0){
3839 av->time_base.den = 5;
3840 av->time_base.num = 1;
3842 if (av->width == 0 || av->height == 0) {
3846 /* Bitrate tolerance is less for streaming */
3847 if (av->bit_rate_tolerance == 0)
3848 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3849 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3854 if (av->max_qdiff == 0)
3856 av->qcompress = 0.5;
3859 if (!av->nsse_weight)
3860 av->nsse_weight = 8;
3862 av->frame_skip_cmp = FF_CMP_DCTMAX;
3864 av->me_method = ME_EPZS;
3865 av->rc_buffer_aggressivity = 1.0;
3868 av->rc_eq = "tex^qComp";
3869 if (!av->i_quant_factor)
3870 av->i_quant_factor = -0.8;
3871 if (!av->b_quant_factor)
3872 av->b_quant_factor = 1.25;
3873 if (!av->b_quant_offset)
3874 av->b_quant_offset = 1.25;
3875 if (!av->rc_max_rate)
3876 av->rc_max_rate = av->bit_rate * 2;
3878 if (av->rc_max_rate && !av->rc_buffer_size) {
3879 av->rc_buffer_size = av->rc_max_rate;
3888 st = av_mallocz(sizeof(AVStream));
3891 st->codec = avcodec_alloc_context();
3892 stream->streams[stream->nb_streams++] = st;
3893 memcpy(st->codec, av, sizeof(AVCodecContext));
3896 static enum CodecID opt_audio_codec(const char *arg)
3898 AVCodec *p= avcodec_find_encoder_by_name(arg);
3900 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3901 return CODEC_ID_NONE;
3906 static enum CodecID opt_video_codec(const char *arg)
3908 AVCodec *p= avcodec_find_encoder_by_name(arg);
3910 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3911 return CODEC_ID_NONE;
3916 /* simplistic plugin support */
3919 static void load_module(const char *filename)
3922 void (*init_func)(void);
3923 dll = dlopen(filename, RTLD_NOW);
3925 fprintf(stderr, "Could not load module '%s' - %s\n",
3926 filename, dlerror());
3930 init_func = dlsym(dll, "ffserver_module_init");
3933 "%s: init function 'ffserver_module_init()' not found\n",
3942 static int ffserver_opt_default(const char *opt, const char *arg,
3943 AVCodecContext *avctx, int type)
3946 const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3948 ret = av_set_string3(avctx, opt, arg, 1, NULL);
3952 static int ffserver_opt_preset(const char *arg,
3953 AVCodecContext *avctx, int type,
3954 enum CodecID *audio_id, enum CodecID *video_id)
3957 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3959 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3961 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3962 codec ? codec->name : NULL))) {
3963 fprintf(stderr, "File for preset '%s' not found\n", arg);
3968 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3969 if(line[0] == '#' && !e)
3971 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3973 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3977 if(!strcmp(tmp, "acodec")){
3978 *audio_id = opt_audio_codec(tmp2);
3979 }else if(!strcmp(tmp, "vcodec")){
3980 *video_id = opt_video_codec(tmp2);
3981 }else if(!strcmp(tmp, "scodec")){
3982 /* opt_subtitle_codec(tmp2); */
3983 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3984 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3995 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
3996 const char *mime_type)
3998 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4001 AVOutputFormat *stream_fmt;
4002 char stream_format_name[64];
4004 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4005 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4014 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4018 fprintf(stderr, "%s:%d: ", filename, line_num);
4019 vfprintf(stderr, fmt, vl);
4025 static int parse_ffconfig(const char *filename)
4032 int val, errors, line_num;
4033 FFStream **last_stream, *stream, *redirect;
4034 FFStream **last_feed, *feed, *s;
4035 AVCodecContext audio_enc, video_enc;
4036 enum CodecID audio_id, video_id;
4038 f = fopen(filename, "r");
4046 first_stream = NULL;
4047 last_stream = &first_stream;
4049 last_feed = &first_feed;
4053 audio_id = CODEC_ID_NONE;
4054 video_id = CODEC_ID_NONE;
4056 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4058 if (fgets(line, sizeof(line), f) == NULL)
4064 if (*p == '\0' || *p == '#')
4067 get_arg(cmd, sizeof(cmd), &p);
4069 if (!strcasecmp(cmd, "Port")) {
4070 get_arg(arg, sizeof(arg), &p);
4072 if (val < 1 || val > 65536) {
4073 ERROR("Invalid_port: %s\n", arg);
4075 my_http_addr.sin_port = htons(val);
4076 } else if (!strcasecmp(cmd, "BindAddress")) {
4077 get_arg(arg, sizeof(arg), &p);
4078 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4079 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4081 } else if (!strcasecmp(cmd, "NoDaemon")) {
4082 ffserver_daemon = 0;
4083 } else if (!strcasecmp(cmd, "RTSPPort")) {
4084 get_arg(arg, sizeof(arg), &p);
4086 if (val < 1 || val > 65536) {
4087 ERROR("%s:%d: Invalid port: %s\n", arg);
4089 my_rtsp_addr.sin_port = htons(atoi(arg));
4090 } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4091 get_arg(arg, sizeof(arg), &p);
4092 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4093 ERROR("Invalid host/IP address: %s\n", arg);
4095 } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4096 get_arg(arg, sizeof(arg), &p);
4098 if (val < 1 || val > 65536) {
4099 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4101 nb_max_http_connections = val;
4102 } else if (!strcasecmp(cmd, "MaxClients")) {
4103 get_arg(arg, sizeof(arg), &p);
4105 if (val < 1 || val > nb_max_http_connections) {
4106 ERROR("Invalid MaxClients: %s\n", arg);
4108 nb_max_connections = val;
4110 } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4112 get_arg(arg, sizeof(arg), &p);
4114 if (llval < 10 || llval > 10000000) {
4115 ERROR("Invalid MaxBandwidth: %s\n", arg);
4117 max_bandwidth = llval;
4118 } else if (!strcasecmp(cmd, "CustomLog")) {
4119 if (!ffserver_debug)
4120 get_arg(logfilename, sizeof(logfilename), &p);
4121 } else if (!strcasecmp(cmd, "<Feed")) {
4122 /*********************************************/
4123 /* Feed related options */
4125 if (stream || feed) {
4126 ERROR("Already in a tag\n");
4128 feed = av_mallocz(sizeof(FFStream));
4129 get_arg(feed->filename, sizeof(feed->filename), &p);
4130 q = strrchr(feed->filename, '>');
4134 for (s = first_feed; s; s = s->next) {
4135 if (!strcmp(feed->filename, s->filename)) {
4136 ERROR("Feed '%s' already registered\n", s->filename);
4140 feed->fmt = av_guess_format("ffm", NULL, NULL);
4141 /* defaut feed file */
4142 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4143 "/tmp/%s.ffm", feed->filename);
4144 feed->feed_max_size = 5 * 1024 * 1024;
4146 feed->feed = feed; /* self feeding :-) */
4148 /* add in stream list */
4149 *last_stream = feed;
4150 last_stream = &feed->next;
4151 /* add in feed list */
4153 last_feed = &feed->next_feed;
4155 } else if (!strcasecmp(cmd, "Launch")) {
4159 feed->child_argv = av_mallocz(64 * sizeof(char *));
4161 for (i = 0; i < 62; i++) {
4162 get_arg(arg, sizeof(arg), &p);
4166 feed->child_argv[i] = av_strdup(arg);
4169 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4171 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4173 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4174 inet_ntoa(my_http_addr.sin_addr),
4175 ntohs(my_http_addr.sin_port), feed->filename);
4177 } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4179 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4181 } else if (stream) {
4182 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4184 } else if (!strcasecmp(cmd, "File")) {
4186 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4188 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4189 } else if (!strcasecmp(cmd, "Truncate")) {
4191 get_arg(arg, sizeof(arg), &p);
4192 feed->truncate = strtod(arg, NULL);
4194 } else if (!strcasecmp(cmd, "FileMaxSize")) {
4199 get_arg(arg, sizeof(arg), &p);
4201 fsize = strtod(p1, &p1);
4202 switch(toupper(*p1)) {
4207 fsize *= 1024 * 1024;
4210 fsize *= 1024 * 1024 * 1024;
4213 feed->feed_max_size = (int64_t)fsize;
4214 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4215 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4218 } else if (!strcasecmp(cmd, "</Feed>")) {
4220 ERROR("No corresponding <Feed> for </Feed>\n");
4223 } else if (!strcasecmp(cmd, "<Stream")) {
4224 /*********************************************/
4225 /* Stream related options */
4227 if (stream || feed) {
4228 ERROR("Already in a tag\n");
4231 stream = av_mallocz(sizeof(FFStream));
4232 get_arg(stream->filename, sizeof(stream->filename), &p);
4233 q = strrchr(stream->filename, '>');
4237 for (s = first_stream; s; s = s->next) {
4238 if (!strcmp(stream->filename, s->filename)) {
4239 ERROR("Stream '%s' already registered\n", s->filename);
4243 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4244 avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4245 avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4246 audio_id = CODEC_ID_NONE;
4247 video_id = CODEC_ID_NONE;
4249 audio_id = stream->fmt->audio_codec;
4250 video_id = stream->fmt->video_codec;
4253 *last_stream = stream;
4254 last_stream = &stream->next;
4256 } else if (!strcasecmp(cmd, "Feed")) {
4257 get_arg(arg, sizeof(arg), &p);
4262 while (sfeed != NULL) {
4263 if (!strcmp(sfeed->filename, arg))
4265 sfeed = sfeed->next_feed;
4268 ERROR("feed '%s' not defined\n", arg);
4270 stream->feed = sfeed;
4272 } else if (!strcasecmp(cmd, "Format")) {
4273 get_arg(arg, sizeof(arg), &p);
4275 if (!strcmp(arg, "status")) {
4276 stream->stream_type = STREAM_TYPE_STATUS;
4279 stream->stream_type = STREAM_TYPE_LIVE;
4280 /* jpeg cannot be used here, so use single frame jpeg */
4281 if (!strcmp(arg, "jpeg"))
4282 strcpy(arg, "mjpeg");
4283 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4285 ERROR("Unknown Format: %s\n", arg);
4289 audio_id = stream->fmt->audio_codec;
4290 video_id = stream->fmt->video_codec;
4293 } else if (!strcasecmp(cmd, "InputFormat")) {
4294 get_arg(arg, sizeof(arg), &p);
4296 stream->ifmt = av_find_input_format(arg);
4297 if (!stream->ifmt) {
4298 ERROR("Unknown input format: %s\n", arg);
4301 } else if (!strcasecmp(cmd, "FaviconURL")) {
4302 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4303 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4305 ERROR("FaviconURL only permitted for status streams\n");
4307 } else if (!strcasecmp(cmd, "Author")) {
4309 get_arg(stream->author, sizeof(stream->author), &p);
4310 } else if (!strcasecmp(cmd, "Comment")) {
4312 get_arg(stream->comment, sizeof(stream->comment), &p);
4313 } else if (!strcasecmp(cmd, "Copyright")) {
4315 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4316 } else if (!strcasecmp(cmd, "Title")) {
4318 get_arg(stream->title, sizeof(stream->title), &p);
4319 } else if (!strcasecmp(cmd, "Preroll")) {
4320 get_arg(arg, sizeof(arg), &p);
4322 stream->prebuffer = atof(arg) * 1000;
4323 } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4325 stream->send_on_key = 1;
4326 } else if (!strcasecmp(cmd, "AudioCodec")) {
4327 get_arg(arg, sizeof(arg), &p);
4328 audio_id = opt_audio_codec(arg);
4329 if (audio_id == CODEC_ID_NONE) {
4330 ERROR("Unknown AudioCodec: %s\n", arg);
4332 } else if (!strcasecmp(cmd, "VideoCodec")) {
4333 get_arg(arg, sizeof(arg), &p);
4334 video_id = opt_video_codec(arg);
4335 if (video_id == CODEC_ID_NONE) {
4336 ERROR("Unknown VideoCodec: %s\n", arg);
4338 } else if (!strcasecmp(cmd, "MaxTime")) {
4339 get_arg(arg, sizeof(arg), &p);
4341 stream->max_time = atof(arg) * 1000;
4342 } else if (!strcasecmp(cmd, "AudioBitRate")) {
4343 get_arg(arg, sizeof(arg), &p);
4345 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4346 } else if (!strcasecmp(cmd, "AudioChannels")) {
4347 get_arg(arg, sizeof(arg), &p);
4349 audio_enc.channels = atoi(arg);
4350 } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4351 get_arg(arg, sizeof(arg), &p);
4353 audio_enc.sample_rate = atoi(arg);
4354 } else if (!strcasecmp(cmd, "AudioQuality")) {
4355 get_arg(arg, sizeof(arg), &p);
4357 // audio_enc.quality = atof(arg) * 1000;
4359 } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4361 int minrate, maxrate;
4363 get_arg(arg, sizeof(arg), &p);
4365 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4366 video_enc.rc_min_rate = minrate * 1000;
4367 video_enc.rc_max_rate = maxrate * 1000;
4369 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4372 } else if (!strcasecmp(cmd, "Debug")) {
4374 get_arg(arg, sizeof(arg), &p);
4375 video_enc.debug = strtol(arg,0,0);
4377 } else if (!strcasecmp(cmd, "Strict")) {
4379 get_arg(arg, sizeof(arg), &p);
4380 video_enc.strict_std_compliance = atoi(arg);
4382 } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4384 get_arg(arg, sizeof(arg), &p);
4385 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4387 } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4389 get_arg(arg, sizeof(arg), &p);
4390 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4392 } else if (!strcasecmp(cmd, "VideoBitRate")) {
4393 get_arg(arg, sizeof(arg), &p);
4395 video_enc.bit_rate = atoi(arg) * 1000;
4397 } else if (!strcasecmp(cmd, "VideoSize")) {
4398 get_arg(arg, sizeof(arg), &p);
4400 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4401 if ((video_enc.width % 16) != 0 ||
4402 (video_enc.height % 16) != 0) {
4403 ERROR("Image size must be a multiple of 16\n");
4406 } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4407 get_arg(arg, sizeof(arg), &p);
4409 AVRational frame_rate;
4410 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4411 ERROR("Incorrect frame rate: %s\n", arg);
4413 video_enc.time_base.num = frame_rate.den;
4414 video_enc.time_base.den = frame_rate.num;
4417 } else if (!strcasecmp(cmd, "VideoGopSize")) {
4418 get_arg(arg, sizeof(arg), &p);
4420 video_enc.gop_size = atoi(arg);
4421 } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4423 video_enc.gop_size = 1;
4424 } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4426 video_enc.mb_decision = FF_MB_DECISION_BITS;
4427 } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4429 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4430 video_enc.flags |= CODEC_FLAG_4MV;
4432 } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4433 !strcasecmp(cmd, "AVOptionAudio")) {
4435 AVCodecContext *avctx;
4437 get_arg(arg, sizeof(arg), &p);
4438 get_arg(arg2, sizeof(arg2), &p);
4439 if (!strcasecmp(cmd, "AVOptionVideo")) {
4441 type = AV_OPT_FLAG_VIDEO_PARAM;
4444 type = AV_OPT_FLAG_AUDIO_PARAM;
4446 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4447 ERROR("AVOption error: %s %s\n", arg, arg2);
4449 } else if (!strcasecmp(cmd, "AVPresetVideo") ||
4450 !strcasecmp(cmd, "AVPresetAudio")) {
4451 AVCodecContext *avctx;
4453 get_arg(arg, sizeof(arg), &p);
4454 if (!strcasecmp(cmd, "AVPresetVideo")) {
4456 video_enc.codec_id = video_id;
4457 type = AV_OPT_FLAG_VIDEO_PARAM;
4460 audio_enc.codec_id = audio_id;
4461 type = AV_OPT_FLAG_AUDIO_PARAM;
4463 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4464 ERROR("AVPreset error: %s\n", arg);
4466 } else if (!strcasecmp(cmd, "VideoTag")) {
4467 get_arg(arg, sizeof(arg), &p);
4468 if ((strlen(arg) == 4) && stream)
4469 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4470 } else if (!strcasecmp(cmd, "BitExact")) {
4472 video_enc.flags |= CODEC_FLAG_BITEXACT;
4473 } else if (!strcasecmp(cmd, "DctFastint")) {
4475 video_enc.dct_algo = FF_DCT_FASTINT;
4476 } else if (!strcasecmp(cmd, "IdctSimple")) {
4478 video_enc.idct_algo = FF_IDCT_SIMPLE;
4479 } else if (!strcasecmp(cmd, "Qscale")) {
4480 get_arg(arg, sizeof(arg), &p);
4482 video_enc.flags |= CODEC_FLAG_QSCALE;
4483 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4485 } else if (!strcasecmp(cmd, "VideoQDiff")) {
4486 get_arg(arg, sizeof(arg), &p);
4488 video_enc.max_qdiff = atoi(arg);
4489 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4490 ERROR("VideoQDiff out of range\n");
4493 } else if (!strcasecmp(cmd, "VideoQMax")) {
4494 get_arg(arg, sizeof(arg), &p);
4496 video_enc.qmax = atoi(arg);
4497 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4498 ERROR("VideoQMax out of range\n");
4501 } else if (!strcasecmp(cmd, "VideoQMin")) {
4502 get_arg(arg, sizeof(arg), &p);
4504 video_enc.qmin = atoi(arg);
4505 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4506 ERROR("VideoQMin out of range\n");
4509 } else if (!strcasecmp(cmd, "LumaElim")) {
4510 get_arg(arg, sizeof(arg), &p);
4512 video_enc.luma_elim_threshold = atoi(arg);
4513 } else if (!strcasecmp(cmd, "ChromaElim")) {
4514 get_arg(arg, sizeof(arg), &p);
4516 video_enc.chroma_elim_threshold = atoi(arg);
4517 } else if (!strcasecmp(cmd, "LumiMask")) {
4518 get_arg(arg, sizeof(arg), &p);
4520 video_enc.lumi_masking = atof(arg);
4521 } else if (!strcasecmp(cmd, "DarkMask")) {
4522 get_arg(arg, sizeof(arg), &p);
4524 video_enc.dark_masking = atof(arg);
4525 } else if (!strcasecmp(cmd, "NoVideo")) {
4526 video_id = CODEC_ID_NONE;
4527 } else if (!strcasecmp(cmd, "NoAudio")) {
4528 audio_id = CODEC_ID_NONE;
4529 } else if (!strcasecmp(cmd, "ACL")) {
4530 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4531 } else if (!strcasecmp(cmd, "DynamicACL")) {
4533 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4535 } else if (!strcasecmp(cmd, "RTSPOption")) {
4536 get_arg(arg, sizeof(arg), &p);
4538 av_freep(&stream->rtsp_option);
4539 stream->rtsp_option = av_strdup(arg);
4541 } else if (!strcasecmp(cmd, "MulticastAddress")) {
4542 get_arg(arg, sizeof(arg), &p);
4544 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4545 ERROR("Invalid host/IP address: %s\n", arg);
4547 stream->is_multicast = 1;
4548 stream->loop = 1; /* default is looping */
4550 } else if (!strcasecmp(cmd, "MulticastPort")) {
4551 get_arg(arg, sizeof(arg), &p);
4553 stream->multicast_port = atoi(arg);
4554 } else if (!strcasecmp(cmd, "MulticastTTL")) {
4555 get_arg(arg, sizeof(arg), &p);
4557 stream->multicast_ttl = atoi(arg);
4558 } else if (!strcasecmp(cmd, "NoLoop")) {
4561 } else if (!strcasecmp(cmd, "</Stream>")) {
4563 ERROR("No corresponding <Stream> for </Stream>\n");
4565 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4566 if (audio_id != CODEC_ID_NONE) {
4567 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4568 audio_enc.codec_id = audio_id;
4569 add_codec(stream, &audio_enc);
4571 if (video_id != CODEC_ID_NONE) {
4572 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4573 video_enc.codec_id = video_id;
4574 add_codec(stream, &video_enc);
4579 } else if (!strcasecmp(cmd, "<Redirect")) {
4580 /*********************************************/
4582 if (stream || feed || redirect) {
4583 ERROR("Already in a tag\n");
4585 redirect = av_mallocz(sizeof(FFStream));
4586 *last_stream = redirect;
4587 last_stream = &redirect->next;
4589 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4590 q = strrchr(redirect->filename, '>');
4593 redirect->stream_type = STREAM_TYPE_REDIRECT;
4595 } else if (!strcasecmp(cmd, "URL")) {
4597 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4598 } else if (!strcasecmp(cmd, "</Redirect>")) {
4600 ERROR("No corresponding <Redirect> for </Redirect>\n");
4602 if (!redirect->feed_filename[0]) {
4603 ERROR("No URL found for <Redirect>\n");
4607 } else if (!strcasecmp(cmd, "LoadModule")) {
4608 get_arg(arg, sizeof(arg), &p);
4612 ERROR("Module support not compiled into this version: '%s'\n", arg);
4615 ERROR("Incorrect keyword: '%s'\n", cmd);
4627 static void handle_child_exit(int sig)
4632 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4635 for (feed = first_feed; feed; feed = feed->next) {
4636 if (feed->pid == pid) {
4637 int uptime = time(0) - feed->pid_start;
4640 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4643 /* Turn off any more restarts */
4644 feed->child_argv = 0;
4649 need_to_start_children = 1;
4652 static void opt_debug(void)
4655 ffserver_daemon = 0;
4656 logfilename[0] = '-';
4659 static void show_help(void)
4661 printf("usage: ffserver [options]\n"
4662 "Hyper fast multi format Audio/Video streaming server\n");
4664 show_help_options(options, "Main options:\n", 0, 0);
4667 static const OptionDef options[] = {
4668 #include "cmdutils_common_opts.h"
4669 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4670 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4671 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4675 int main(int argc, char **argv)
4677 struct sigaction sigact;
4683 my_program_name = argv[0];
4684 my_program_dir = getcwd(0, 0);
4685 ffserver_daemon = 1;
4687 parse_options(argc, argv, options, NULL);
4689 unsetenv("http_proxy"); /* Kill the http_proxy */
4691 av_lfg_init(&random_state, av_get_random_seed());
4693 memset(&sigact, 0, sizeof(sigact));
4694 sigact.sa_handler = handle_child_exit;
4695 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4696 sigaction(SIGCHLD, &sigact, 0);
4698 if (parse_ffconfig(config_filename) < 0) {
4699 fprintf(stderr, "Incorrect config file - exiting.\n");
4703 /* open log file if needed */
4704 if (logfilename[0] != '\0') {
4705 if (!strcmp(logfilename, "-"))
4708 logfile = fopen(logfilename, "a");
4709 av_log_set_callback(http_av_log);
4712 build_file_streams();
4714 build_feed_streams();
4716 compute_bandwidth();
4718 /* put the process in background and detach it from its TTY */
4719 if (ffserver_daemon) {
4726 } else if (pid > 0) {
4733 open("/dev/null", O_RDWR);
4734 if (strcmp(logfilename, "-") != 0) {
4744 signal(SIGPIPE, SIG_IGN);
4746 if (ffserver_daemon)
4749 if (http_server() < 0) {
4750 http_log("Could not start server\n");