2 * Multiple format streaming server
3 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
5 * This file is part of Libav.
7 * Libav is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * Libav is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #define _XOPEN_SOURCE 600
26 #define closesocket close
31 #include "libavformat/avformat.h"
32 #include "libavformat/network.h"
33 #include "libavformat/os_support.h"
34 #include "libavformat/rtpdec.h"
35 #include "libavformat/rtsp.h"
36 // XXX for ffio_open_dyn_packet_buffer, to be removed
37 #include "libavformat/avio_internal.h"
38 #include "libavutil/avstring.h"
39 #include "libavutil/lfg.h"
40 #include "libavutil/random_seed.h"
41 #include "libavutil/parseutils.h"
42 #include "libavcodec/opt.h"
46 #include <sys/ioctl.h>
61 const char program_name[] = "FFserver";
62 const int program_birth_year = 2000;
64 static const OptionDef options[];
67 HTTPSTATE_WAIT_REQUEST,
68 HTTPSTATE_SEND_HEADER,
69 HTTPSTATE_SEND_DATA_HEADER,
70 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
71 HTTPSTATE_SEND_DATA_TRAILER,
72 HTTPSTATE_RECEIVE_DATA,
73 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
76 RTSPSTATE_WAIT_REQUEST,
78 RTSPSTATE_SEND_PACKET,
81 static const char *http_state[] = {
97 #if !FF_API_MAX_STREAMS
98 #define MAX_STREAMS 20
101 #define IOBUFFER_INIT_SIZE 8192
103 /* timeouts are in ms */
104 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
105 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
107 #define SYNC_TIMEOUT (10 * 1000)
109 typedef struct RTSPActionServerSetup {
111 char transport_option[512];
112 } RTSPActionServerSetup;
115 int64_t count1, count2;
116 int64_t time1, time2;
119 /* context associated with one connection */
120 typedef struct HTTPContext {
121 enum HTTPState state;
122 int fd; /* socket file descriptor */
123 struct sockaddr_in from_addr; /* origin */
124 struct pollfd *poll_entry; /* used when polling */
126 uint8_t *buffer_ptr, *buffer_end;
129 int chunked_encoding;
130 int chunk_size; /* 0 if it needs to be read */
131 struct HTTPContext *next;
132 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
136 /* input format handling */
137 AVFormatContext *fmt_in;
138 int64_t start_time; /* In milliseconds - this wraps fairly often */
139 int64_t first_pts; /* initial pts value */
140 int64_t cur_pts; /* current pts value from the stream in us */
141 int64_t cur_frame_duration; /* duration of the current frame in us */
142 int cur_frame_bytes; /* output frame size, needed to compute
143 the time at which we send each
145 int pts_stream_index; /* stream we choose as clock reference */
146 int64_t cur_clock; /* current clock reference value in us */
147 /* output format handling */
148 struct FFStream *stream;
149 /* -1 is invalid stream */
150 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
151 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
153 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
154 int last_packet_sent; /* true if last data packet was sent */
156 DataRateData datarate;
163 int is_packetized; /* if true, the stream is packetized */
164 int packet_stream_index; /* current stream for output in state machine */
166 /* RTSP state specific */
167 uint8_t *pb_buffer; /* XXX: use that in all the code */
169 int seq; /* RTSP sequence number */
171 /* RTP state specific */
172 enum RTSPLowerTransport rtp_protocol;
173 char session_id[32]; /* session id */
174 AVFormatContext *rtp_ctx[MAX_STREAMS];
176 /* RTP/UDP specific */
177 URLContext *rtp_handles[MAX_STREAMS];
179 /* RTP/TCP specific */
180 struct HTTPContext *rtsp_c;
181 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
184 /* each generated stream is described here */
188 STREAM_TYPE_REDIRECT,
191 enum IPAddressAction {
196 typedef struct IPAddressACL {
197 struct IPAddressACL *next;
198 enum IPAddressAction action;
199 /* These are in host order */
200 struct in_addr first;
204 /* description of each stream of the ffserver.conf file */
205 typedef struct FFStream {
206 enum StreamType stream_type;
207 char filename[1024]; /* stream filename */
208 struct FFStream *feed; /* feed we are using (can be null if
210 AVFormatParameters *ap_in; /* input parameters */
211 AVInputFormat *ifmt; /* if non NULL, force input format */
214 char dynamic_acl[1024];
216 int prebuffer; /* Number of millseconds early to start */
217 int64_t max_time; /* Number of milliseconds to run */
219 AVStream *streams[MAX_STREAMS];
220 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
221 char feed_filename[1024]; /* file name of the feed storage, or
222 input file name for a stream */
227 pid_t pid; /* Of ffmpeg process */
228 time_t pid_start; /* Of ffmpeg process */
230 struct FFStream *next;
231 unsigned bandwidth; /* bandwidth, in kbits/s */
234 /* multicast specific */
236 struct in_addr multicast_ip;
237 int multicast_port; /* first port used for multicast */
239 int loop; /* if true, send the stream in loops (only meaningful if file) */
242 int feed_opened; /* true if someone is writing to the feed */
243 int is_feed; /* true if it is a feed */
244 int readonly; /* True if writing is prohibited to the file */
245 int truncate; /* True if feeder connection truncate the feed file */
247 int64_t bytes_served;
248 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
249 int64_t feed_write_index; /* current write position in feed (it wraps around) */
250 int64_t feed_size; /* current size of feed */
251 struct FFStream *next_feed;
254 typedef struct FeedData {
255 long long data_count;
256 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
259 static struct sockaddr_in my_http_addr;
260 static struct sockaddr_in my_rtsp_addr;
262 static char logfilename[1024];
263 static HTTPContext *first_http_ctx;
264 static FFStream *first_feed; /* contains only feeds */
265 static FFStream *first_stream; /* contains all streams, including feeds */
267 static void new_connection(int server_fd, int is_rtsp);
268 static void close_connection(HTTPContext *c);
271 static int handle_connection(HTTPContext *c);
272 static int http_parse_request(HTTPContext *c);
273 static int http_send_data(HTTPContext *c);
274 static void compute_status(HTTPContext *c);
275 static int open_input_stream(HTTPContext *c, const char *info);
276 static int http_start_receive_data(HTTPContext *c);
277 static int http_receive_data(HTTPContext *c);
280 static int rtsp_parse_request(HTTPContext *c);
281 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
282 static void rtsp_cmd_options(HTTPContext *c, const char *url);
283 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
284 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
285 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
286 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
289 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
290 struct in_addr my_ip);
293 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
294 FFStream *stream, const char *session_id,
295 enum RTSPLowerTransport rtp_protocol);
296 static int rtp_new_av_stream(HTTPContext *c,
297 int stream_index, struct sockaddr_in *dest_addr,
298 HTTPContext *rtsp_c);
300 static const char *my_program_name;
301 static const char *my_program_dir;
303 static const char *config_filename = "/etc/ffserver.conf";
305 static int ffserver_debug;
306 static int ffserver_daemon;
307 static int no_launch;
308 static int need_to_start_children;
310 /* maximum number of simultaneous HTTP connections */
311 static unsigned int nb_max_http_connections = 2000;
312 static unsigned int nb_max_connections = 5;
313 static unsigned int nb_connections;
315 static uint64_t max_bandwidth = 1000;
316 static uint64_t current_bandwidth;
318 static int64_t cur_time; // Making this global saves on passing it around everywhere
320 static AVLFG random_state;
322 static FILE *logfile = NULL;
324 /* FIXME: make ffserver work with IPv6 */
325 /* resolve host with also IP address parsing */
326 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
329 if (!ff_inet_aton(hostname, sin_addr)) {
331 struct addrinfo *ai, *cur;
332 struct addrinfo hints;
333 memset(&hints, 0, sizeof(hints));
334 hints.ai_family = AF_INET;
335 if (getaddrinfo(hostname, NULL, &hints, &ai))
337 /* getaddrinfo returns a linked list of addrinfo structs.
338 * Even if we set ai_family = AF_INET above, make sure
339 * that the returned one actually is of the correct type. */
340 for (cur = ai; cur; cur = cur->ai_next) {
341 if (cur->ai_family == AF_INET) {
342 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
351 hp = gethostbyname(hostname);
354 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
360 static char *ctime1(char *buf2)
368 p = buf2 + strlen(p) - 1;
374 static void http_vlog(const char *fmt, va_list vargs)
376 static int print_prefix = 1;
381 fprintf(logfile, "%s ", buf);
383 print_prefix = strstr(fmt, "\n") != NULL;
384 vfprintf(logfile, fmt, vargs);
390 __attribute__ ((format (printf, 1, 2)))
392 static void http_log(const char *fmt, ...)
395 va_start(vargs, fmt);
396 http_vlog(fmt, vargs);
400 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
402 static int print_prefix = 1;
403 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
404 if (level > av_log_get_level())
406 if (print_prefix && avc)
407 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
408 print_prefix = strstr(fmt, "\n") != NULL;
409 http_vlog(fmt, vargs);
412 static void log_connection(HTTPContext *c)
417 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
418 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
419 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
422 static void update_datarate(DataRateData *drd, int64_t count)
424 if (!drd->time1 && !drd->count1) {
425 drd->time1 = drd->time2 = cur_time;
426 drd->count1 = drd->count2 = count;
427 } else if (cur_time - drd->time2 > 5000) {
428 drd->time1 = drd->time2;
429 drd->count1 = drd->count2;
430 drd->time2 = cur_time;
435 /* In bytes per second */
436 static int compute_datarate(DataRateData *drd, int64_t count)
438 if (cur_time == drd->time1)
441 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
445 static void start_children(FFStream *feed)
450 for (; feed; feed = feed->next) {
451 if (feed->child_argv && !feed->pid) {
452 feed->pid_start = time(0);
457 http_log("Unable to create children\n");
466 av_strlcpy(pathname, my_program_name, sizeof(pathname));
468 slash = strrchr(pathname, '/');
473 strcpy(slash, "ffmpeg");
475 http_log("Launch commandline: ");
476 http_log("%s ", pathname);
477 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
478 http_log("%s ", feed->child_argv[i]);
481 for (i = 3; i < 256; i++)
484 if (!ffserver_debug) {
485 i = open("/dev/null", O_RDWR);
494 /* This is needed to make relative pathnames work */
495 chdir(my_program_dir);
497 signal(SIGPIPE, SIG_DFL);
499 execvp(pathname, feed->child_argv);
507 /* open a listening socket */
508 static int socket_open_listen(struct sockaddr_in *my_addr)
512 server_fd = socket(AF_INET,SOCK_STREAM,0);
519 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
521 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
523 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
525 closesocket(server_fd);
529 if (listen (server_fd, 5) < 0) {
531 closesocket(server_fd);
534 ff_socket_nonblock(server_fd, 1);
539 /* start all multicast streams */
540 static void start_multicast(void)
545 struct sockaddr_in dest_addr;
546 int default_port, stream_index;
549 for(stream = first_stream; stream != NULL; stream = stream->next) {
550 if (stream->is_multicast) {
551 /* open the RTP connection */
552 snprintf(session_id, sizeof(session_id), "%08x%08x",
553 av_lfg_get(&random_state), av_lfg_get(&random_state));
555 /* choose a port if none given */
556 if (stream->multicast_port == 0) {
557 stream->multicast_port = default_port;
561 dest_addr.sin_family = AF_INET;
562 dest_addr.sin_addr = stream->multicast_ip;
563 dest_addr.sin_port = htons(stream->multicast_port);
565 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
566 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
570 if (open_input_stream(rtp_c, "") < 0) {
571 http_log("Could not open input stream for stream '%s'\n",
576 /* open each RTP stream */
577 for(stream_index = 0; stream_index < stream->nb_streams;
579 dest_addr.sin_port = htons(stream->multicast_port +
581 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
582 http_log("Could not open output stream '%s/streamid=%d'\n",
583 stream->filename, stream_index);
588 /* change state to send data */
589 rtp_c->state = HTTPSTATE_SEND_DATA;
594 /* main loop of the http server */
595 static int http_server(void)
597 int server_fd = 0, rtsp_server_fd = 0;
598 int ret, delay, delay1;
599 struct pollfd *poll_table, *poll_entry;
600 HTTPContext *c, *c_next;
602 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
603 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
607 if (my_http_addr.sin_port) {
608 server_fd = socket_open_listen(&my_http_addr);
613 if (my_rtsp_addr.sin_port) {
614 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
615 if (rtsp_server_fd < 0)
619 if (!rtsp_server_fd && !server_fd) {
620 http_log("HTTP and RTSP disabled.\n");
624 http_log("FFserver started.\n");
626 start_children(first_feed);
631 poll_entry = poll_table;
633 poll_entry->fd = server_fd;
634 poll_entry->events = POLLIN;
637 if (rtsp_server_fd) {
638 poll_entry->fd = rtsp_server_fd;
639 poll_entry->events = POLLIN;
643 /* wait for events on each HTTP handle */
650 case HTTPSTATE_SEND_HEADER:
651 case RTSPSTATE_SEND_REPLY:
652 case RTSPSTATE_SEND_PACKET:
653 c->poll_entry = poll_entry;
655 poll_entry->events = POLLOUT;
658 case HTTPSTATE_SEND_DATA_HEADER:
659 case HTTPSTATE_SEND_DATA:
660 case HTTPSTATE_SEND_DATA_TRAILER:
661 if (!c->is_packetized) {
662 /* for TCP, we output as much as we can (may need to put a limit) */
663 c->poll_entry = poll_entry;
665 poll_entry->events = POLLOUT;
668 /* when ffserver is doing the timing, we work by
669 looking at which packet need to be sent every
671 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
676 case HTTPSTATE_WAIT_REQUEST:
677 case HTTPSTATE_RECEIVE_DATA:
678 case HTTPSTATE_WAIT_FEED:
679 case RTSPSTATE_WAIT_REQUEST:
680 /* need to catch errors */
681 c->poll_entry = poll_entry;
683 poll_entry->events = POLLIN;/* Maybe this will work */
687 c->poll_entry = NULL;
693 /* wait for an event on one connection. We poll at least every
694 second to handle timeouts */
696 ret = poll(poll_table, poll_entry - poll_table, delay);
697 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
698 ff_neterrno() != AVERROR(EINTR))
702 cur_time = av_gettime() / 1000;
704 if (need_to_start_children) {
705 need_to_start_children = 0;
706 start_children(first_feed);
709 /* now handle the events */
710 for(c = first_http_ctx; c != NULL; c = c_next) {
712 if (handle_connection(c) < 0) {
713 /* close and free the connection */
719 poll_entry = poll_table;
721 /* new HTTP connection request ? */
722 if (poll_entry->revents & POLLIN)
723 new_connection(server_fd, 0);
726 if (rtsp_server_fd) {
727 /* new RTSP connection request ? */
728 if (poll_entry->revents & POLLIN)
729 new_connection(rtsp_server_fd, 1);
734 /* start waiting for a new HTTP/RTSP request */
735 static void start_wait_request(HTTPContext *c, int is_rtsp)
737 c->buffer_ptr = c->buffer;
738 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
741 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
742 c->state = RTSPSTATE_WAIT_REQUEST;
744 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
745 c->state = HTTPSTATE_WAIT_REQUEST;
749 static void http_send_too_busy_reply(int fd)
752 int len = snprintf(buffer, sizeof(buffer),
753 "HTTP/1.0 503 Server too busy\r\n"
754 "Content-type: text/html\r\n"
756 "<html><head><title>Too busy</title></head><body>\r\n"
757 "<p>The server is too busy to serve your request at this time.</p>\r\n"
758 "<p>The number of current connections is %d, and this exceeds the limit of %d.</p>\r\n"
759 "</body></html>\r\n",
760 nb_connections, nb_max_connections);
761 send(fd, buffer, len, 0);
765 static void new_connection(int server_fd, int is_rtsp)
767 struct sockaddr_in from_addr;
769 HTTPContext *c = NULL;
771 len = sizeof(from_addr);
772 fd = accept(server_fd, (struct sockaddr *)&from_addr,
775 http_log("error during accept %s\n", strerror(errno));
778 ff_socket_nonblock(fd, 1);
780 if (nb_connections >= nb_max_connections) {
781 http_send_too_busy_reply(fd);
785 /* add a new connection */
786 c = av_mallocz(sizeof(HTTPContext));
791 c->poll_entry = NULL;
792 c->from_addr = from_addr;
793 c->buffer_size = IOBUFFER_INIT_SIZE;
794 c->buffer = av_malloc(c->buffer_size);
798 c->next = first_http_ctx;
802 start_wait_request(c, is_rtsp);
814 static void close_connection(HTTPContext *c)
816 HTTPContext **cp, *c1;
818 AVFormatContext *ctx;
822 /* remove connection from list */
823 cp = &first_http_ctx;
824 while ((*cp) != NULL) {
832 /* remove references, if any (XXX: do it faster) */
833 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
838 /* remove connection associated resources */
842 /* close each frame parser */
843 for(i=0;i<c->fmt_in->nb_streams;i++) {
844 st = c->fmt_in->streams[i];
845 if (st->codec->codec)
846 avcodec_close(st->codec);
848 av_close_input_file(c->fmt_in);
851 /* free RTP output streams if any */
854 nb_streams = c->stream->nb_streams;
856 for(i=0;i<nb_streams;i++) {
859 av_write_trailer(ctx);
860 av_metadata_free(&ctx->metadata);
861 av_free(ctx->streams[0]);
864 h = c->rtp_handles[i];
871 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
874 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
875 av_write_trailer(ctx);
876 av_freep(&c->pb_buffer);
877 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
882 for(i=0; i<ctx->nb_streams; i++)
883 av_free(ctx->streams[i]);
885 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
886 current_bandwidth -= c->stream->bandwidth;
888 /* signal that there is no feed if we are the feeder socket */
889 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
890 c->stream->feed_opened = 0;
894 av_freep(&c->pb_buffer);
895 av_freep(&c->packet_buffer);
901 static int handle_connection(HTTPContext *c)
906 case HTTPSTATE_WAIT_REQUEST:
907 case RTSPSTATE_WAIT_REQUEST:
909 if ((c->timeout - cur_time) < 0)
911 if (c->poll_entry->revents & (POLLERR | POLLHUP))
914 /* no need to read if no events */
915 if (!(c->poll_entry->revents & POLLIN))
919 len = recv(c->fd, c->buffer_ptr, 1, 0);
921 if (ff_neterrno() != AVERROR(EAGAIN) &&
922 ff_neterrno() != AVERROR(EINTR))
924 } else if (len == 0) {
927 /* search for end of request. */
929 c->buffer_ptr += len;
931 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
932 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
933 /* request found : parse it and reply */
934 if (c->state == HTTPSTATE_WAIT_REQUEST) {
935 ret = http_parse_request(c);
937 ret = rtsp_parse_request(c);
941 } else if (ptr >= c->buffer_end) {
942 /* request too long: cannot do anything */
944 } else goto read_loop;
948 case HTTPSTATE_SEND_HEADER:
949 if (c->poll_entry->revents & (POLLERR | POLLHUP))
952 /* no need to write if no events */
953 if (!(c->poll_entry->revents & POLLOUT))
955 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
957 if (ff_neterrno() != AVERROR(EAGAIN) &&
958 ff_neterrno() != AVERROR(EINTR)) {
959 /* error : close connection */
960 av_freep(&c->pb_buffer);
964 c->buffer_ptr += len;
966 c->stream->bytes_served += len;
967 c->data_count += len;
968 if (c->buffer_ptr >= c->buffer_end) {
969 av_freep(&c->pb_buffer);
973 /* all the buffer was sent : synchronize to the incoming stream */
974 c->state = HTTPSTATE_SEND_DATA_HEADER;
975 c->buffer_ptr = c->buffer_end = c->buffer;
980 case HTTPSTATE_SEND_DATA:
981 case HTTPSTATE_SEND_DATA_HEADER:
982 case HTTPSTATE_SEND_DATA_TRAILER:
983 /* for packetized output, we consider we can always write (the
984 input streams sets the speed). It may be better to verify
985 that we do not rely too much on the kernel queues */
986 if (!c->is_packetized) {
987 if (c->poll_entry->revents & (POLLERR | POLLHUP))
990 /* no need to read if no events */
991 if (!(c->poll_entry->revents & POLLOUT))
994 if (http_send_data(c) < 0)
996 /* close connection if trailer sent */
997 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1000 case HTTPSTATE_RECEIVE_DATA:
1001 /* no need to read if no events */
1002 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1004 if (!(c->poll_entry->revents & POLLIN))
1006 if (http_receive_data(c) < 0)
1009 case HTTPSTATE_WAIT_FEED:
1010 /* no need to read if no events */
1011 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1014 /* nothing to do, we'll be waken up by incoming feed packets */
1017 case RTSPSTATE_SEND_REPLY:
1018 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1019 av_freep(&c->pb_buffer);
1022 /* no need to write if no events */
1023 if (!(c->poll_entry->revents & POLLOUT))
1025 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1027 if (ff_neterrno() != AVERROR(EAGAIN) &&
1028 ff_neterrno() != AVERROR(EINTR)) {
1029 /* error : close connection */
1030 av_freep(&c->pb_buffer);
1034 c->buffer_ptr += len;
1035 c->data_count += len;
1036 if (c->buffer_ptr >= c->buffer_end) {
1037 /* all the buffer was sent : wait for a new request */
1038 av_freep(&c->pb_buffer);
1039 start_wait_request(c, 1);
1043 case RTSPSTATE_SEND_PACKET:
1044 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1045 av_freep(&c->packet_buffer);
1048 /* no need to write if no events */
1049 if (!(c->poll_entry->revents & POLLOUT))
1051 len = send(c->fd, c->packet_buffer_ptr,
1052 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1054 if (ff_neterrno() != AVERROR(EAGAIN) &&
1055 ff_neterrno() != AVERROR(EINTR)) {
1056 /* error : close connection */
1057 av_freep(&c->packet_buffer);
1061 c->packet_buffer_ptr += len;
1062 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1063 /* all the buffer was sent : wait for a new request */
1064 av_freep(&c->packet_buffer);
1065 c->state = RTSPSTATE_WAIT_REQUEST;
1069 case HTTPSTATE_READY:
1078 static int extract_rates(char *rates, int ratelen, const char *request)
1082 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1083 if (strncasecmp(p, "Pragma:", 7) == 0) {
1084 const char *q = p + 7;
1086 while (*q && *q != '\n' && isspace(*q))
1089 if (strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1095 memset(rates, 0xff, ratelen);
1098 while (*q && *q != '\n' && *q != ':')
1101 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1105 if (stream_no < ratelen && stream_no >= 0)
1106 rates[stream_no] = rate_no;
1108 while (*q && *q != '\n' && !isspace(*q))
1115 p = strchr(p, '\n');
1125 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1128 int best_bitrate = 100000000;
1131 for (i = 0; i < feed->nb_streams; i++) {
1132 AVCodecContext *feed_codec = feed->streams[i]->codec;
1134 if (feed_codec->codec_id != codec->codec_id ||
1135 feed_codec->sample_rate != codec->sample_rate ||
1136 feed_codec->width != codec->width ||
1137 feed_codec->height != codec->height)
1140 /* Potential stream */
1142 /* We want the fastest stream less than bit_rate, or the slowest
1143 * faster than bit_rate
1146 if (feed_codec->bit_rate <= bit_rate) {
1147 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1148 best_bitrate = feed_codec->bit_rate;
1152 if (feed_codec->bit_rate < best_bitrate) {
1153 best_bitrate = feed_codec->bit_rate;
1162 static int modify_current_stream(HTTPContext *c, char *rates)
1165 FFStream *req = c->stream;
1166 int action_required = 0;
1168 /* Not much we can do for a feed */
1172 for (i = 0; i < req->nb_streams; i++) {
1173 AVCodecContext *codec = req->streams[i]->codec;
1177 c->switch_feed_streams[i] = req->feed_streams[i];
1180 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1183 /* Wants off or slow */
1184 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1186 /* This doesn't work well when it turns off the only stream! */
1187 c->switch_feed_streams[i] = -2;
1188 c->feed_streams[i] = -2;
1193 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1194 action_required = 1;
1197 return action_required;
1200 /* XXX: factorize in utils.c ? */
1201 /* XXX: take care with different space meaning */
1202 static void skip_spaces(const char **pp)
1206 while (*p == ' ' || *p == '\t')
1211 static void get_word(char *buf, int buf_size, const char **pp)
1219 while (!isspace(*p) && *p != '\0') {
1220 if ((q - buf) < buf_size - 1)
1229 static void get_arg(char *buf, int buf_size, const char **pp)
1236 while (isspace(*p)) p++;
1239 if (*p == '\"' || *p == '\'')
1251 if ((q - buf) < buf_size - 1)
1256 if (quote && *p == quote)
1261 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1262 const char *p, const char *filename, int line_num)
1268 get_arg(arg, sizeof(arg), &p);
1269 if (strcasecmp(arg, "allow") == 0)
1270 acl.action = IP_ALLOW;
1271 else if (strcasecmp(arg, "deny") == 0)
1272 acl.action = IP_DENY;
1274 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1275 filename, line_num, arg);
1279 get_arg(arg, sizeof(arg), &p);
1281 if (resolve_host(&acl.first, arg) != 0) {
1282 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1283 filename, line_num, arg);
1286 acl.last = acl.first;
1288 get_arg(arg, sizeof(arg), &p);
1291 if (resolve_host(&acl.last, arg) != 0) {
1292 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1293 filename, line_num, arg);
1299 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1300 IPAddressACL **naclp = 0;
1306 naclp = &stream->acl;
1312 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1313 filename, line_num);
1319 naclp = &(*naclp)->next;
1327 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1332 IPAddressACL *acl = NULL;
1336 f = fopen(stream->dynamic_acl, "r");
1338 perror(stream->dynamic_acl);
1342 acl = av_mallocz(sizeof(IPAddressACL));
1346 if (fgets(line, sizeof(line), f) == NULL)
1352 if (*p == '\0' || *p == '#')
1354 get_arg(cmd, sizeof(cmd), &p);
1356 if (!strcasecmp(cmd, "ACL"))
1357 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1364 static void free_acl_list(IPAddressACL *in_acl)
1366 IPAddressACL *pacl,*pacl2;
1376 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1378 enum IPAddressAction last_action = IP_DENY;
1380 struct in_addr *src = &c->from_addr.sin_addr;
1381 unsigned long src_addr = src->s_addr;
1383 for (acl = in_acl; acl; acl = acl->next) {
1384 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1385 return (acl->action == IP_ALLOW) ? 1 : 0;
1386 last_action = acl->action;
1389 /* Nothing matched, so return not the last action */
1390 return (last_action == IP_DENY) ? 1 : 0;
1393 static int validate_acl(FFStream *stream, HTTPContext *c)
1399 /* if stream->acl is null validate_acl_list will return 1 */
1400 ret = validate_acl_list(stream->acl, c);
1402 if (stream->dynamic_acl[0]) {
1403 acl = parse_dynamic_acl(stream, c);
1405 ret = validate_acl_list(acl, c);
1413 /* compute the real filename of a file by matching it without its
1414 extensions to all the stream filenames */
1415 static void compute_real_filename(char *filename, int max_size)
1422 /* compute filename by matching without the file extensions */
1423 av_strlcpy(file1, filename, sizeof(file1));
1424 p = strrchr(file1, '.');
1427 for(stream = first_stream; stream != NULL; stream = stream->next) {
1428 av_strlcpy(file2, stream->filename, sizeof(file2));
1429 p = strrchr(file2, '.');
1432 if (!strcmp(file1, file2)) {
1433 av_strlcpy(filename, stream->filename, max_size);
1448 /* parse http request and prepare header */
1449 static int http_parse_request(HTTPContext *c)
1452 enum RedirType redir_type;
1454 char info[1024], filename[1024];
1458 const char *mime_type;
1462 char *useragent = 0;
1465 get_word(cmd, sizeof(cmd), (const char **)&p);
1466 av_strlcpy(c->method, cmd, sizeof(c->method));
1468 if (!strcmp(cmd, "GET"))
1470 else if (!strcmp(cmd, "POST"))
1475 get_word(url, sizeof(url), (const char **)&p);
1476 av_strlcpy(c->url, url, sizeof(c->url));
1478 get_word(protocol, sizeof(protocol), (const char **)&p);
1479 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1482 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1485 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1487 /* find the filename and the optional info string in the request */
1488 p = strchr(url, '?');
1490 av_strlcpy(info, p, sizeof(info));
1495 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1497 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1498 if (strncasecmp(p, "User-Agent:", 11) == 0) {
1500 if (*useragent && *useragent != '\n' && isspace(*useragent))
1504 p = strchr(p, '\n');
1511 redir_type = REDIR_NONE;
1512 if (av_match_ext(filename, "asx")) {
1513 redir_type = REDIR_ASX;
1514 filename[strlen(filename)-1] = 'f';
1515 } else if (av_match_ext(filename, "asf") &&
1516 (!useragent || strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1517 /* if this isn't WMP or lookalike, return the redirector file */
1518 redir_type = REDIR_ASF;
1519 } else if (av_match_ext(filename, "rpm,ram")) {
1520 redir_type = REDIR_RAM;
1521 strcpy(filename + strlen(filename)-2, "m");
1522 } else if (av_match_ext(filename, "rtsp")) {
1523 redir_type = REDIR_RTSP;
1524 compute_real_filename(filename, sizeof(filename) - 1);
1525 } else if (av_match_ext(filename, "sdp")) {
1526 redir_type = REDIR_SDP;
1527 compute_real_filename(filename, sizeof(filename) - 1);
1530 // "redirect" / request to index.html
1531 if (!strlen(filename))
1532 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1534 stream = first_stream;
1535 while (stream != NULL) {
1536 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1538 stream = stream->next;
1540 if (stream == NULL) {
1541 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1542 http_log("File '%s' not found\n", url);
1547 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1548 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1550 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1551 c->http_error = 301;
1553 q += snprintf(q, c->buffer_size,
1554 "HTTP/1.0 301 Moved\r\n"
1556 "Content-type: text/html\r\n"
1558 "<html><head><title>Moved</title></head><body>\r\n"
1559 "You should be <a href=\"%s\">redirected</a>.\r\n"
1560 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1561 /* prepare output buffer */
1562 c->buffer_ptr = c->buffer;
1564 c->state = HTTPSTATE_SEND_HEADER;
1568 /* If this is WMP, get the rate information */
1569 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1570 if (modify_current_stream(c, ratebuf)) {
1571 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1572 if (c->switch_feed_streams[i] >= 0)
1573 c->switch_feed_streams[i] = -1;
1578 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1579 current_bandwidth += stream->bandwidth;
1581 /* If already streaming this feed, do not let start another feeder. */
1582 if (stream->feed_opened) {
1583 snprintf(msg, sizeof(msg), "This feed is already being received.");
1584 http_log("Feed '%s' already being received\n", stream->feed_filename);
1588 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1589 c->http_error = 503;
1591 q += snprintf(q, c->buffer_size,
1592 "HTTP/1.0 503 Server too busy\r\n"
1593 "Content-type: text/html\r\n"
1595 "<html><head><title>Too busy</title></head><body>\r\n"
1596 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1597 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1598 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1599 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1600 /* prepare output buffer */
1601 c->buffer_ptr = c->buffer;
1603 c->state = HTTPSTATE_SEND_HEADER;
1607 if (redir_type != REDIR_NONE) {
1610 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1611 if (strncasecmp(p, "Host:", 5) == 0) {
1615 p = strchr(p, '\n');
1626 while (isspace(*hostinfo))
1629 eoh = strchr(hostinfo, '\n');
1631 if (eoh[-1] == '\r')
1634 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1635 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1636 hostbuf[eoh - hostinfo] = 0;
1638 c->http_error = 200;
1640 switch(redir_type) {
1642 q += snprintf(q, c->buffer_size,
1643 "HTTP/1.0 200 ASX Follows\r\n"
1644 "Content-type: video/x-ms-asf\r\n"
1646 "<ASX Version=\"3\">\r\n"
1647 //"<!-- Autogenerated by ffserver -->\r\n"
1648 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1649 "</ASX>\r\n", hostbuf, filename, info);
1652 q += snprintf(q, c->buffer_size,
1653 "HTTP/1.0 200 RAM Follows\r\n"
1654 "Content-type: audio/x-pn-realaudio\r\n"
1656 "# Autogenerated by ffserver\r\n"
1657 "http://%s/%s%s\r\n", hostbuf, filename, info);
1660 q += snprintf(q, c->buffer_size,
1661 "HTTP/1.0 200 ASF Redirect follows\r\n"
1662 "Content-type: video/x-ms-asf\r\n"
1665 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1669 char hostname[256], *p;
1670 /* extract only hostname */
1671 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1672 p = strrchr(hostname, ':');
1675 q += snprintf(q, c->buffer_size,
1676 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1677 /* XXX: incorrect mime type ? */
1678 "Content-type: application/x-rtsp\r\n"
1680 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1686 int sdp_data_size, len;
1687 struct sockaddr_in my_addr;
1689 q += snprintf(q, c->buffer_size,
1690 "HTTP/1.0 200 OK\r\n"
1691 "Content-type: application/sdp\r\n"
1694 len = sizeof(my_addr);
1695 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1697 /* XXX: should use a dynamic buffer */
1698 sdp_data_size = prepare_sdp_description(stream,
1701 if (sdp_data_size > 0) {
1702 memcpy(q, sdp_data, sdp_data_size);
1714 /* prepare output buffer */
1715 c->buffer_ptr = c->buffer;
1717 c->state = HTTPSTATE_SEND_HEADER;
1723 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1727 stream->conns_served++;
1729 /* XXX: add there authenticate and IP match */
1732 /* if post, it means a feed is being sent */
1733 if (!stream->is_feed) {
1734 /* However it might be a status report from WMP! Let us log the
1735 * data as it might come in handy one day. */
1739 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1740 if (strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1744 if (strncasecmp(p, "Pragma: client-id=", 18) == 0)
1745 client_id = strtol(p + 18, 0, 10);
1746 p = strchr(p, '\n');
1754 char *eol = strchr(logline, '\n');
1759 if (eol[-1] == '\r')
1761 http_log("%.*s\n", (int) (eol - logline), logline);
1762 c->suppress_log = 1;
1767 http_log("\nGot request:\n%s\n", c->buffer);
1770 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1773 /* Now we have to find the client_id */
1774 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1775 if (wmpc->wmp_client_id == client_id)
1779 if (wmpc && modify_current_stream(wmpc, ratebuf))
1780 wmpc->switch_pending = 1;
1783 snprintf(msg, sizeof(msg), "POST command not handled");
1787 if (http_start_receive_data(c) < 0) {
1788 snprintf(msg, sizeof(msg), "could not open feed");
1792 c->state = HTTPSTATE_RECEIVE_DATA;
1797 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1798 http_log("\nGot request:\n%s\n", c->buffer);
1801 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1804 /* open input stream */
1805 if (open_input_stream(c, info) < 0) {
1806 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1810 /* prepare http header */
1812 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "HTTP/1.0 200 OK\r\n");
1813 mime_type = c->stream->fmt->mime_type;
1815 mime_type = "application/x-octet-stream";
1816 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Pragma: no-cache\r\n");
1818 /* for asf, we need extra headers */
1819 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1820 /* Need to allocate a client id */
1822 c->wmp_client_id = av_lfg_get(&random_state);
1824 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);
1826 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "Content-Type: %s\r\n", mime_type);
1827 q += snprintf(q, q - (char *) c->buffer + c->buffer_size, "\r\n");
1829 /* prepare output buffer */
1831 c->buffer_ptr = c->buffer;
1833 c->state = HTTPSTATE_SEND_HEADER;
1836 c->http_error = 404;
1838 q += snprintf(q, c->buffer_size,
1839 "HTTP/1.0 404 Not Found\r\n"
1840 "Content-type: text/html\r\n"
1843 "<head><title>404 Not Found</title></head>\n"
1846 /* prepare output buffer */
1847 c->buffer_ptr = c->buffer;
1849 c->state = HTTPSTATE_SEND_HEADER;
1853 c->http_error = 200; /* horrible : we use this value to avoid
1854 going to the send data state */
1855 c->state = HTTPSTATE_SEND_HEADER;
1859 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1861 static const char *suffix = " kMGTP";
1864 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1866 avio_printf(pb, "%"PRId64"%c", count, *s);
1869 static void compute_status(HTTPContext *c)
1878 if (avio_open_dyn_buf(&pb) < 0) {
1879 /* XXX: return an error ? */
1880 c->buffer_ptr = c->buffer;
1881 c->buffer_end = c->buffer;
1885 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1886 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1887 avio_printf(pb, "Pragma: no-cache\r\n");
1888 avio_printf(pb, "\r\n");
1890 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1891 if (c->stream->feed_filename[0])
1892 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1893 avio_printf(pb, "</head>\n<body>");
1894 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1896 avio_printf(pb, "<h2>Available Streams</h2>\n");
1897 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1898 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");
1899 stream = first_stream;
1900 while (stream != NULL) {
1901 char sfilename[1024];
1904 if (stream->feed != stream) {
1905 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1906 eosf = sfilename + strlen(sfilename);
1907 if (eosf - sfilename >= 4) {
1908 if (strcmp(eosf - 4, ".asf") == 0)
1909 strcpy(eosf - 4, ".asx");
1910 else if (strcmp(eosf - 3, ".rm") == 0)
1911 strcpy(eosf - 3, ".ram");
1912 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1913 /* generate a sample RTSP director if
1914 unicast. Generate an SDP redirector if
1916 eosf = strrchr(sfilename, '.');
1918 eosf = sfilename + strlen(sfilename);
1919 if (stream->is_multicast)
1920 strcpy(eosf, ".sdp");
1922 strcpy(eosf, ".rtsp");
1926 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1927 sfilename, stream->filename);
1928 avio_printf(pb, "<td align=right> %d <td align=right> ",
1929 stream->conns_served);
1930 fmt_bytecount(pb, stream->bytes_served);
1931 switch(stream->stream_type) {
1932 case STREAM_TYPE_LIVE: {
1933 int audio_bit_rate = 0;
1934 int video_bit_rate = 0;
1935 const char *audio_codec_name = "";
1936 const char *video_codec_name = "";
1937 const char *audio_codec_name_extra = "";
1938 const char *video_codec_name_extra = "";
1940 for(i=0;i<stream->nb_streams;i++) {
1941 AVStream *st = stream->streams[i];
1942 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
1943 switch(st->codec->codec_type) {
1944 case AVMEDIA_TYPE_AUDIO:
1945 audio_bit_rate += st->codec->bit_rate;
1947 if (*audio_codec_name)
1948 audio_codec_name_extra = "...";
1949 audio_codec_name = codec->name;
1952 case AVMEDIA_TYPE_VIDEO:
1953 video_bit_rate += st->codec->bit_rate;
1955 if (*video_codec_name)
1956 video_codec_name_extra = "...";
1957 video_codec_name = codec->name;
1960 case AVMEDIA_TYPE_DATA:
1961 video_bit_rate += st->codec->bit_rate;
1967 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",
1970 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
1971 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
1973 avio_printf(pb, "<td>%s", stream->feed->filename);
1975 avio_printf(pb, "<td>%s", stream->feed_filename);
1976 avio_printf(pb, "\n");
1980 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
1984 stream = stream->next;
1986 avio_printf(pb, "</table>\n");
1988 stream = first_stream;
1989 while (stream != NULL) {
1990 if (stream->feed == stream) {
1991 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
1993 avio_printf(pb, "Running as pid %d.\n", stream->pid);
1995 #if defined(linux) && !defined(CONFIG_NOCUTILS)
2000 /* This is somewhat linux specific I guess */
2001 snprintf(ps_cmd, sizeof(ps_cmd),
2002 "ps -o \"%%cpu,cputime\" --no-headers %d",
2005 pid_stat = popen(ps_cmd, "r");
2010 if (fscanf(pid_stat, "%10s %64s", cpuperc,
2012 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2020 avio_printf(pb, "<p>");
2022 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");
2024 for (i = 0; i < stream->nb_streams; i++) {
2025 AVStream *st = stream->streams[i];
2026 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2027 const char *type = "unknown";
2028 char parameters[64];
2032 switch(st->codec->codec_type) {
2033 case AVMEDIA_TYPE_AUDIO:
2035 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2037 case AVMEDIA_TYPE_VIDEO:
2039 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2040 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2045 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2046 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2048 avio_printf(pb, "</table>\n");
2051 stream = stream->next;
2054 /* connection status */
2055 avio_printf(pb, "<h2>Connection Status</h2>\n");
2057 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2058 nb_connections, nb_max_connections);
2060 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2061 current_bandwidth, max_bandwidth);
2063 avio_printf(pb, "<table>\n");
2064 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");
2065 c1 = first_http_ctx;
2067 while (c1 != NULL) {
2073 for (j = 0; j < c1->stream->nb_streams; j++) {
2074 if (!c1->stream->feed)
2075 bitrate += c1->stream->streams[j]->codec->bit_rate;
2076 else if (c1->feed_streams[j] >= 0)
2077 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2082 p = inet_ntoa(c1->from_addr.sin_addr);
2083 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2085 c1->stream ? c1->stream->filename : "",
2086 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2089 http_state[c1->state]);
2090 fmt_bytecount(pb, bitrate);
2091 avio_printf(pb, "<td align=right>");
2092 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2093 avio_printf(pb, "<td align=right>");
2094 fmt_bytecount(pb, c1->data_count);
2095 avio_printf(pb, "\n");
2098 avio_printf(pb, "</table>\n");
2103 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2104 avio_printf(pb, "</body>\n</html>\n");
2106 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2107 c->buffer_ptr = c->pb_buffer;
2108 c->buffer_end = c->pb_buffer + len;
2111 /* check if the parser needs to be opened for stream i */
2112 static void open_parser(AVFormatContext *s, int i)
2114 AVStream *st = s->streams[i];
2117 if (!st->codec->codec) {
2118 codec = avcodec_find_decoder(st->codec->codec_id);
2119 if (codec && (codec->capabilities & CODEC_CAP_PARSE_ONLY)) {
2120 st->codec->parse_only = 1;
2121 if (avcodec_open(st->codec, codec) < 0)
2122 st->codec->parse_only = 0;
2127 static int open_input_stream(HTTPContext *c, const char *info)
2130 char input_filename[1024];
2132 int buf_size, i, ret;
2135 /* find file name */
2136 if (c->stream->feed) {
2137 strcpy(input_filename, c->stream->feed->feed_filename);
2138 buf_size = FFM_PACKET_SIZE;
2139 /* compute position (absolute time) */
2140 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2141 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0)
2143 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2144 int prebuffer = strtol(buf, 0, 10);
2145 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2147 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2149 strcpy(input_filename, c->stream->feed_filename);
2151 /* compute position (relative time) */
2152 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2153 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0)
2158 if (input_filename[0] == '\0')
2162 if ((ret = av_open_input_file(&s, input_filename, c->stream->ifmt,
2163 buf_size, c->stream->ap_in)) < 0) {
2164 http_log("could not open %s: %d\n", input_filename, ret);
2167 s->flags |= AVFMT_FLAG_GENPTS;
2169 if (strcmp(s->iformat->name, "ffm") && av_find_stream_info(c->fmt_in) < 0) {
2170 http_log("Could not find stream info '%s'\n", input_filename);
2171 av_close_input_file(s);
2175 /* open each parser */
2176 for(i=0;i<s->nb_streams;i++)
2179 /* choose stream as clock source (we favorize video stream if
2180 present) for packet sending */
2181 c->pts_stream_index = 0;
2182 for(i=0;i<c->stream->nb_streams;i++) {
2183 if (c->pts_stream_index == 0 &&
2184 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2185 c->pts_stream_index = i;
2190 if (c->fmt_in->iformat->read_seek)
2191 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2193 /* set the start time (needed for maxtime and RTP packet timing) */
2194 c->start_time = cur_time;
2195 c->first_pts = AV_NOPTS_VALUE;
2199 /* return the server clock (in us) */
2200 static int64_t get_server_clock(HTTPContext *c)
2202 /* compute current pts value from system time */
2203 return (cur_time - c->start_time) * 1000;
2206 /* return the estimated time at which the current packet must be sent
2208 static int64_t get_packet_send_clock(HTTPContext *c)
2210 int bytes_left, bytes_sent, frame_bytes;
2212 frame_bytes = c->cur_frame_bytes;
2213 if (frame_bytes <= 0)
2216 bytes_left = c->buffer_end - c->buffer_ptr;
2217 bytes_sent = frame_bytes - bytes_left;
2218 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2223 static int http_prepare_data(HTTPContext *c)
2226 AVFormatContext *ctx;
2228 av_freep(&c->pb_buffer);
2230 case HTTPSTATE_SEND_DATA_HEADER:
2231 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2232 av_metadata_set2(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2233 av_metadata_set2(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2234 av_metadata_set2(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2235 av_metadata_set2(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2237 for(i=0;i<c->stream->nb_streams;i++) {
2240 st = av_mallocz(sizeof(AVStream));
2241 c->fmt_ctx.streams[i] = st;
2242 /* if file or feed, then just take streams from FFStream struct */
2243 if (!c->stream->feed ||
2244 c->stream->feed == c->stream)
2245 src = c->stream->streams[i];
2247 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2251 st->codec->frame_number = 0; /* XXX: should be done in
2252 AVStream, not in codec */
2254 /* set output format parameters */
2255 c->fmt_ctx.oformat = c->stream->fmt;
2256 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2258 c->got_key_frame = 0;
2260 /* prepare header and save header data in a stream */
2261 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2262 /* XXX: potential leak */
2265 c->fmt_ctx.pb->seekable = 0;
2268 * HACK to avoid mpeg ps muxer to spit many underflow errors
2269 * Default value from FFmpeg
2270 * Try to set it use configuration option
2272 c->fmt_ctx.preload = (int)(0.5*AV_TIME_BASE);
2273 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2275 av_set_parameters(&c->fmt_ctx, NULL);
2276 if (av_write_header(&c->fmt_ctx) < 0) {
2277 http_log("Error writing output header\n");
2280 av_metadata_free(&c->fmt_ctx.metadata);
2282 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2283 c->buffer_ptr = c->pb_buffer;
2284 c->buffer_end = c->pb_buffer + len;
2286 c->state = HTTPSTATE_SEND_DATA;
2287 c->last_packet_sent = 0;
2289 case HTTPSTATE_SEND_DATA:
2290 /* find a new packet */
2291 /* read a packet from the input stream */
2292 if (c->stream->feed)
2293 ffm_set_write_index(c->fmt_in,
2294 c->stream->feed->feed_write_index,
2295 c->stream->feed->feed_size);
2297 if (c->stream->max_time &&
2298 c->stream->max_time + c->start_time - cur_time < 0)
2299 /* We have timed out */
2300 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2304 ret = av_read_frame(c->fmt_in, &pkt);
2306 if (c->stream->feed) {
2307 /* if coming from feed, it means we reached the end of the
2308 ffm file, so must wait for more data */
2309 c->state = HTTPSTATE_WAIT_FEED;
2310 return 1; /* state changed */
2311 } else if (ret == AVERROR(EAGAIN)) {
2312 /* input not ready, come back later */
2315 if (c->stream->loop) {
2316 av_close_input_file(c->fmt_in);
2318 if (open_input_stream(c, "") < 0)
2323 /* must send trailer now because eof or error */
2324 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2328 int source_index = pkt.stream_index;
2329 /* update first pts if needed */
2330 if (c->first_pts == AV_NOPTS_VALUE) {
2331 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2332 c->start_time = cur_time;
2334 /* send it to the appropriate stream */
2335 if (c->stream->feed) {
2336 /* if coming from a feed, select the right stream */
2337 if (c->switch_pending) {
2338 c->switch_pending = 0;
2339 for(i=0;i<c->stream->nb_streams;i++) {
2340 if (c->switch_feed_streams[i] == pkt.stream_index)
2341 if (pkt.flags & AV_PKT_FLAG_KEY)
2342 c->switch_feed_streams[i] = -1;
2343 if (c->switch_feed_streams[i] >= 0)
2344 c->switch_pending = 1;
2347 for(i=0;i<c->stream->nb_streams;i++) {
2348 if (c->stream->feed_streams[i] == pkt.stream_index) {
2349 AVStream *st = c->fmt_in->streams[source_index];
2350 pkt.stream_index = i;
2351 if (pkt.flags & AV_PKT_FLAG_KEY &&
2352 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2353 c->stream->nb_streams == 1))
2354 c->got_key_frame = 1;
2355 if (!c->stream->send_on_key || c->got_key_frame)
2360 AVCodecContext *codec;
2361 AVStream *ist, *ost;
2363 ist = c->fmt_in->streams[source_index];
2364 /* specific handling for RTP: we use several
2365 output stream (one for each RTP
2366 connection). XXX: need more abstract handling */
2367 if (c->is_packetized) {
2368 /* compute send time and duration */
2369 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2370 c->cur_pts -= c->first_pts;
2371 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2372 /* find RTP context */
2373 c->packet_stream_index = pkt.stream_index;
2374 ctx = c->rtp_ctx[c->packet_stream_index];
2376 av_free_packet(&pkt);
2379 codec = ctx->streams[0]->codec;
2380 /* only one stream per RTP connection */
2381 pkt.stream_index = 0;
2385 codec = ctx->streams[pkt.stream_index]->codec;
2388 if (c->is_packetized) {
2389 int max_packet_size;
2390 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2391 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2393 max_packet_size = url_get_max_packet_size(c->rtp_handles[c->packet_stream_index]);
2394 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2396 ret = avio_open_dyn_buf(&ctx->pb);
2399 /* XXX: potential leak */
2402 ost = ctx->streams[pkt.stream_index];
2404 ctx->pb->seekable = 0;
2405 if (pkt.dts != AV_NOPTS_VALUE)
2406 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2407 if (pkt.pts != AV_NOPTS_VALUE)
2408 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2409 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2410 if (av_write_frame(ctx, &pkt) < 0) {
2411 http_log("Error writing frame to output\n");
2412 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2415 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2416 c->cur_frame_bytes = len;
2417 c->buffer_ptr = c->pb_buffer;
2418 c->buffer_end = c->pb_buffer + len;
2420 codec->frame_number++;
2422 av_free_packet(&pkt);
2426 av_free_packet(&pkt);
2431 case HTTPSTATE_SEND_DATA_TRAILER:
2432 /* last packet test ? */
2433 if (c->last_packet_sent || c->is_packetized)
2436 /* prepare header */
2437 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2438 /* XXX: potential leak */
2441 c->fmt_ctx.pb->seekable = 0;
2442 av_write_trailer(ctx);
2443 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2444 c->buffer_ptr = c->pb_buffer;
2445 c->buffer_end = c->pb_buffer + len;
2447 c->last_packet_sent = 1;
2453 /* should convert the format at the same time */
2454 /* send data starting at c->buffer_ptr to the output connection
2455 (either UDP or TCP connection) */
2456 static int http_send_data(HTTPContext *c)
2461 if (c->buffer_ptr >= c->buffer_end) {
2462 ret = http_prepare_data(c);
2466 /* state change requested */
2469 if (c->is_packetized) {
2470 /* RTP data output */
2471 len = c->buffer_end - c->buffer_ptr;
2473 /* fail safe - should never happen */
2475 c->buffer_ptr = c->buffer_end;
2478 len = (c->buffer_ptr[0] << 24) |
2479 (c->buffer_ptr[1] << 16) |
2480 (c->buffer_ptr[2] << 8) |
2482 if (len > (c->buffer_end - c->buffer_ptr))
2484 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2485 /* nothing to send yet: we can wait */
2489 c->data_count += len;
2490 update_datarate(&c->datarate, c->data_count);
2492 c->stream->bytes_served += len;
2494 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2495 /* RTP packets are sent inside the RTSP TCP connection */
2497 int interleaved_index, size;
2499 HTTPContext *rtsp_c;
2502 /* if no RTSP connection left, error */
2505 /* if already sending something, then wait. */
2506 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2508 if (avio_open_dyn_buf(&pb) < 0)
2510 interleaved_index = c->packet_stream_index * 2;
2511 /* RTCP packets are sent at odd indexes */
2512 if (c->buffer_ptr[1] == 200)
2513 interleaved_index++;
2514 /* write RTSP TCP header */
2516 header[1] = interleaved_index;
2517 header[2] = len >> 8;
2519 avio_write(pb, header, 4);
2520 /* write RTP packet data */
2522 avio_write(pb, c->buffer_ptr, len);
2523 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2524 /* prepare asynchronous TCP sending */
2525 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2526 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2527 c->buffer_ptr += len;
2529 /* send everything we can NOW */
2530 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2531 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2533 rtsp_c->packet_buffer_ptr += len;
2534 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2535 /* if we could not send all the data, we will
2536 send it later, so a new state is needed to
2537 "lock" the RTSP TCP connection */
2538 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2541 /* all data has been sent */
2542 av_freep(&c->packet_buffer);
2544 /* send RTP packet directly in UDP */
2546 url_write(c->rtp_handles[c->packet_stream_index],
2547 c->buffer_ptr, len);
2548 c->buffer_ptr += len;
2549 /* here we continue as we can send several packets per 10 ms slot */
2552 /* TCP data output */
2553 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2555 if (ff_neterrno() != AVERROR(EAGAIN) &&
2556 ff_neterrno() != AVERROR(EINTR))
2557 /* error : close connection */
2562 c->buffer_ptr += len;
2564 c->data_count += len;
2565 update_datarate(&c->datarate, c->data_count);
2567 c->stream->bytes_served += len;
2575 static int http_start_receive_data(HTTPContext *c)
2579 if (c->stream->feed_opened)
2582 /* Don't permit writing to this one */
2583 if (c->stream->readonly)
2587 fd = open(c->stream->feed_filename, O_RDWR);
2589 http_log("Error opening feeder file: %s\n", strerror(errno));
2594 if (c->stream->truncate) {
2595 /* truncate feed file */
2596 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2597 ftruncate(c->feed_fd, FFM_PACKET_SIZE);
2598 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2600 if ((c->stream->feed_write_index = ffm_read_write_index(fd)) < 0) {
2601 http_log("Error reading write index from feed file: %s\n", strerror(errno));
2606 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2607 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2608 lseek(fd, 0, SEEK_SET);
2610 /* init buffer input */
2611 c->buffer_ptr = c->buffer;
2612 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2613 c->stream->feed_opened = 1;
2614 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2618 static int http_receive_data(HTTPContext *c)
2621 int len, loop_run = 0;
2623 while (c->chunked_encoding && !c->chunk_size &&
2624 c->buffer_end > c->buffer_ptr) {
2625 /* read chunk header, if present */
2626 len = recv(c->fd, c->buffer_ptr, 1, 0);
2629 if (ff_neterrno() != AVERROR(EAGAIN) &&
2630 ff_neterrno() != AVERROR(EINTR))
2631 /* error : close connection */
2634 } else if (len == 0) {
2635 /* end of connection : close it */
2637 } else if (c->buffer_ptr - c->buffer >= 2 &&
2638 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2639 c->chunk_size = strtol(c->buffer, 0, 16);
2640 if (c->chunk_size == 0) // end of stream
2642 c->buffer_ptr = c->buffer;
2644 } else if (++loop_run > 10) {
2645 /* no chunk header, abort */
2652 if (c->buffer_end > c->buffer_ptr) {
2653 len = recv(c->fd, c->buffer_ptr,
2654 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2656 if (ff_neterrno() != AVERROR(EAGAIN) &&
2657 ff_neterrno() != AVERROR(EINTR))
2658 /* error : close connection */
2660 } else if (len == 0)
2661 /* end of connection : close it */
2664 c->chunk_size -= len;
2665 c->buffer_ptr += len;
2666 c->data_count += len;
2667 update_datarate(&c->datarate, c->data_count);
2671 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2672 if (c->buffer[0] != 'f' ||
2673 c->buffer[1] != 'm') {
2674 http_log("Feed stream has become desynchronized -- disconnecting\n");
2679 if (c->buffer_ptr >= c->buffer_end) {
2680 FFStream *feed = c->stream;
2681 /* a packet has been received : write it in the store, except
2683 if (c->data_count > FFM_PACKET_SIZE) {
2685 // printf("writing pos=0x%"PRIx64" size=0x%"PRIx64"\n", feed->feed_write_index, feed->feed_size);
2686 /* XXX: use llseek or url_seek */
2687 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2688 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2689 http_log("Error writing to feed file: %s\n", strerror(errno));
2693 feed->feed_write_index += FFM_PACKET_SIZE;
2694 /* update file size */
2695 if (feed->feed_write_index > c->stream->feed_size)
2696 feed->feed_size = feed->feed_write_index;
2698 /* handle wrap around if max file size reached */
2699 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2700 feed->feed_write_index = FFM_PACKET_SIZE;
2703 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2704 http_log("Error writing index to feed file: %s\n", strerror(errno));
2708 /* wake up any waiting connections */
2709 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2710 if (c1->state == HTTPSTATE_WAIT_FEED &&
2711 c1->stream->feed == c->stream->feed)
2712 c1->state = HTTPSTATE_SEND_DATA;
2715 /* We have a header in our hands that contains useful data */
2716 AVFormatContext *s = NULL;
2718 AVInputFormat *fmt_in;
2721 /* use feed output format name to find corresponding input format */
2722 fmt_in = av_find_input_format(feed->fmt->name);
2726 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2727 0, NULL, NULL, NULL, NULL);
2730 if (av_open_input_stream(&s, pb, c->stream->feed_filename, fmt_in, NULL) < 0) {
2735 /* Now we have the actual streams */
2736 if (s->nb_streams != feed->nb_streams) {
2737 av_close_input_stream(s);
2739 http_log("Feed '%s' stream number does not match registered feed\n",
2740 c->stream->feed_filename);
2744 for (i = 0; i < s->nb_streams; i++) {
2745 AVStream *fst = feed->streams[i];
2746 AVStream *st = s->streams[i];
2747 avcodec_copy_context(fst->codec, st->codec);
2750 av_close_input_stream(s);
2753 c->buffer_ptr = c->buffer;
2758 c->stream->feed_opened = 0;
2760 /* wake up any waiting connections to stop waiting for feed */
2761 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2762 if (c1->state == HTTPSTATE_WAIT_FEED &&
2763 c1->stream->feed == c->stream->feed)
2764 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2769 /********************************************************************/
2772 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2779 switch(error_number) {
2780 case RTSP_STATUS_OK:
2783 case RTSP_STATUS_METHOD:
2784 str = "Method Not Allowed";
2786 case RTSP_STATUS_BANDWIDTH:
2787 str = "Not Enough Bandwidth";
2789 case RTSP_STATUS_SESSION:
2790 str = "Session Not Found";
2792 case RTSP_STATUS_STATE:
2793 str = "Method Not Valid in This State";
2795 case RTSP_STATUS_AGGREGATE:
2796 str = "Aggregate operation not allowed";
2798 case RTSP_STATUS_ONLY_AGGREGATE:
2799 str = "Only aggregate operation allowed";
2801 case RTSP_STATUS_TRANSPORT:
2802 str = "Unsupported transport";
2804 case RTSP_STATUS_INTERNAL:
2805 str = "Internal Server Error";
2807 case RTSP_STATUS_SERVICE:
2808 str = "Service Unavailable";
2810 case RTSP_STATUS_VERSION:
2811 str = "RTSP Version not supported";
2814 str = "Unknown Error";
2818 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2819 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2821 /* output GMT time */
2824 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2825 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2828 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2830 rtsp_reply_header(c, error_number);
2831 avio_printf(c->pb, "\r\n");
2834 static int rtsp_parse_request(HTTPContext *c)
2836 const char *p, *p1, *p2;
2842 RTSPMessageHeader header1, *header = &header1;
2844 c->buffer_ptr[0] = '\0';
2847 get_word(cmd, sizeof(cmd), &p);
2848 get_word(url, sizeof(url), &p);
2849 get_word(protocol, sizeof(protocol), &p);
2851 av_strlcpy(c->method, cmd, sizeof(c->method));
2852 av_strlcpy(c->url, url, sizeof(c->url));
2853 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2855 if (avio_open_dyn_buf(&c->pb) < 0) {
2856 /* XXX: cannot do more */
2857 c->pb = NULL; /* safety */
2861 /* check version name */
2862 if (strcmp(protocol, "RTSP/1.0") != 0) {
2863 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2867 /* parse each header line */
2868 memset(header, 0, sizeof(*header));
2869 /* skip to next line */
2870 while (*p != '\n' && *p != '\0')
2874 while (*p != '\0') {
2875 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2879 if (p2 > p && p2[-1] == '\r')
2881 /* skip empty line */
2885 if (len > sizeof(line) - 1)
2886 len = sizeof(line) - 1;
2887 memcpy(line, p, len);
2889 ff_rtsp_parse_line(header, line, NULL, NULL);
2893 /* handle sequence number */
2894 c->seq = header->seq;
2896 if (!strcmp(cmd, "DESCRIBE"))
2897 rtsp_cmd_describe(c, url);
2898 else if (!strcmp(cmd, "OPTIONS"))
2899 rtsp_cmd_options(c, url);
2900 else if (!strcmp(cmd, "SETUP"))
2901 rtsp_cmd_setup(c, url, header);
2902 else if (!strcmp(cmd, "PLAY"))
2903 rtsp_cmd_play(c, url, header);
2904 else if (!strcmp(cmd, "PAUSE"))
2905 rtsp_cmd_pause(c, url, header);
2906 else if (!strcmp(cmd, "TEARDOWN"))
2907 rtsp_cmd_teardown(c, url, header);
2909 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2912 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2913 c->pb = NULL; /* safety */
2915 /* XXX: cannot do more */
2918 c->buffer_ptr = c->pb_buffer;
2919 c->buffer_end = c->pb_buffer + len;
2920 c->state = RTSPSTATE_SEND_REPLY;
2924 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2925 struct in_addr my_ip)
2927 AVFormatContext *avc;
2928 AVStream *avs = NULL;
2931 avc = avformat_alloc_context();
2935 av_metadata_set2(&avc->metadata, "title",
2936 stream->title[0] ? stream->title : "No Title", 0);
2937 avc->nb_streams = stream->nb_streams;
2938 if (stream->is_multicast) {
2939 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2940 inet_ntoa(stream->multicast_ip),
2941 stream->multicast_port, stream->multicast_ttl);
2943 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2946 #if !FF_API_MAX_STREAMS
2947 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2948 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2951 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2952 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2955 for(i = 0; i < stream->nb_streams; i++) {
2956 avc->streams[i] = &avs[i];
2957 avc->streams[i]->codec = stream->streams[i]->codec;
2959 *pbuffer = av_mallocz(2048);
2960 avf_sdp_create(&avc, 1, *pbuffer, 2048);
2963 #if !FF_API_MAX_STREAMS
2964 av_free(avc->streams);
2966 av_metadata_free(&avc->metadata);
2970 return strlen(*pbuffer);
2973 static void rtsp_cmd_options(HTTPContext *c, const char *url)
2975 // rtsp_reply_header(c, RTSP_STATUS_OK);
2976 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
2977 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2978 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
2979 avio_printf(c->pb, "\r\n");
2982 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
2988 int content_length, len;
2989 struct sockaddr_in my_addr;
2991 /* find which url is asked */
2992 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
2997 for(stream = first_stream; stream != NULL; stream = stream->next) {
2998 if (!stream->is_feed &&
2999 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3000 !strcmp(path, stream->filename)) {
3004 /* no stream found */
3005 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3009 /* prepare the media description in sdp format */
3011 /* get the host IP */
3012 len = sizeof(my_addr);
3013 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3014 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3015 if (content_length < 0) {
3016 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3019 rtsp_reply_header(c, RTSP_STATUS_OK);
3020 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3021 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3022 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3023 avio_printf(c->pb, "\r\n");
3024 avio_write(c->pb, content, content_length);
3028 static HTTPContext *find_rtp_session(const char *session_id)
3032 if (session_id[0] == '\0')
3035 for(c = first_http_ctx; c != NULL; c = c->next) {
3036 if (!strcmp(c->session_id, session_id))
3042 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3044 RTSPTransportField *th;
3047 for(i=0;i<h->nb_transports;i++) {
3048 th = &h->transports[i];
3049 if (th->lower_transport == lower_transport)
3055 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3056 RTSPMessageHeader *h)
3059 int stream_index, rtp_port, rtcp_port;
3064 RTSPTransportField *th;
3065 struct sockaddr_in dest_addr;
3066 RTSPActionServerSetup setup;
3068 /* find which url is asked */
3069 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3074 /* now check each stream */
3075 for(stream = first_stream; stream != NULL; stream = stream->next) {
3076 if (!stream->is_feed &&
3077 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3078 /* accept aggregate filenames only if single stream */
3079 if (!strcmp(path, stream->filename)) {
3080 if (stream->nb_streams != 1) {
3081 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3088 for(stream_index = 0; stream_index < stream->nb_streams;
3090 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3091 stream->filename, stream_index);
3092 if (!strcmp(path, buf))
3097 /* no stream found */
3098 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3102 /* generate session id if needed */
3103 if (h->session_id[0] == '\0')
3104 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3105 av_lfg_get(&random_state), av_lfg_get(&random_state));
3107 /* find rtp session, and create it if none found */
3108 rtp_c = find_rtp_session(h->session_id);
3110 /* always prefer UDP */
3111 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3113 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3115 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3120 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3121 th->lower_transport);
3123 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3127 /* open input stream */
3128 if (open_input_stream(rtp_c, "") < 0) {
3129 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3134 /* test if stream is OK (test needed because several SETUP needs
3135 to be done for a given file) */
3136 if (rtp_c->stream != stream) {
3137 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3141 /* test if stream is already set up */
3142 if (rtp_c->rtp_ctx[stream_index]) {
3143 rtsp_reply_error(c, RTSP_STATUS_STATE);
3147 /* check transport */
3148 th = find_transport(h, rtp_c->rtp_protocol);
3149 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3150 th->client_port_min <= 0)) {
3151 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3155 /* setup default options */
3156 setup.transport_option[0] = '\0';
3157 dest_addr = rtp_c->from_addr;
3158 dest_addr.sin_port = htons(th->client_port_min);
3161 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3162 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3166 /* now everything is OK, so we can send the connection parameters */
3167 rtsp_reply_header(c, RTSP_STATUS_OK);
3169 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3171 switch(rtp_c->rtp_protocol) {
3172 case RTSP_LOWER_TRANSPORT_UDP:
3173 rtp_port = rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3174 rtcp_port = rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3175 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3176 "client_port=%d-%d;server_port=%d-%d",
3177 th->client_port_min, th->client_port_max,
3178 rtp_port, rtcp_port);
3180 case RTSP_LOWER_TRANSPORT_TCP:
3181 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3182 stream_index * 2, stream_index * 2 + 1);
3187 if (setup.transport_option[0] != '\0')
3188 avio_printf(c->pb, ";%s", setup.transport_option);
3189 avio_printf(c->pb, "\r\n");
3192 avio_printf(c->pb, "\r\n");
3196 /* find an rtp connection by using the session ID. Check consistency
3198 static HTTPContext *find_rtp_session_with_url(const char *url,
3199 const char *session_id)
3207 rtp_c = find_rtp_session(session_id);
3211 /* find which url is asked */
3212 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3216 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3217 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3218 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3219 rtp_c->stream->filename, s);
3220 if(!strncmp(path, buf, sizeof(buf))) {
3221 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3226 if (len > 0 && path[len - 1] == '/' &&
3227 !strncmp(path, rtp_c->stream->filename, len - 1))
3232 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3236 rtp_c = find_rtp_session_with_url(url, h->session_id);
3238 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3242 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3243 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3244 rtp_c->state != HTTPSTATE_READY) {
3245 rtsp_reply_error(c, RTSP_STATUS_STATE);
3249 rtp_c->state = HTTPSTATE_SEND_DATA;
3251 /* now everything is OK, so we can send the connection parameters */
3252 rtsp_reply_header(c, RTSP_STATUS_OK);
3254 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3255 avio_printf(c->pb, "\r\n");
3258 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3262 rtp_c = find_rtp_session_with_url(url, h->session_id);
3264 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3268 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3269 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3270 rtsp_reply_error(c, RTSP_STATUS_STATE);
3274 rtp_c->state = HTTPSTATE_READY;
3275 rtp_c->first_pts = AV_NOPTS_VALUE;
3276 /* now everything is OK, so we can send the connection parameters */
3277 rtsp_reply_header(c, RTSP_STATUS_OK);
3279 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3280 avio_printf(c->pb, "\r\n");
3283 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3286 char session_id[32];
3288 rtp_c = find_rtp_session_with_url(url, h->session_id);
3290 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3294 av_strlcpy(session_id, rtp_c->session_id, sizeof(session_id));
3296 /* abort the session */
3297 close_connection(rtp_c);
3299 /* now everything is OK, so we can send the connection parameters */
3300 rtsp_reply_header(c, RTSP_STATUS_OK);
3302 avio_printf(c->pb, "Session: %s\r\n", session_id);
3303 avio_printf(c->pb, "\r\n");
3307 /********************************************************************/
3310 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3311 FFStream *stream, const char *session_id,
3312 enum RTSPLowerTransport rtp_protocol)
3314 HTTPContext *c = NULL;
3315 const char *proto_str;
3317 /* XXX: should output a warning page when coming
3318 close to the connection limit */
3319 if (nb_connections >= nb_max_connections)
3322 /* add a new connection */
3323 c = av_mallocz(sizeof(HTTPContext));
3328 c->poll_entry = NULL;
3329 c->from_addr = *from_addr;
3330 c->buffer_size = IOBUFFER_INIT_SIZE;
3331 c->buffer = av_malloc(c->buffer_size);
3336 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3337 c->state = HTTPSTATE_READY;
3338 c->is_packetized = 1;
3339 c->rtp_protocol = rtp_protocol;
3341 /* protocol is shown in statistics */
3342 switch(c->rtp_protocol) {
3343 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3344 proto_str = "MCAST";
3346 case RTSP_LOWER_TRANSPORT_UDP:
3349 case RTSP_LOWER_TRANSPORT_TCP:
3356 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3357 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3359 current_bandwidth += stream->bandwidth;
3361 c->next = first_http_ctx;
3373 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3374 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3376 static int rtp_new_av_stream(HTTPContext *c,
3377 int stream_index, struct sockaddr_in *dest_addr,
3378 HTTPContext *rtsp_c)
3380 AVFormatContext *ctx;
3383 URLContext *h = NULL;
3385 int max_packet_size;
3387 /* now we can open the relevant output stream */
3388 ctx = avformat_alloc_context();
3391 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3393 st = av_mallocz(sizeof(AVStream));
3396 ctx->nb_streams = 1;
3397 ctx->streams[0] = st;
3399 if (!c->stream->feed ||
3400 c->stream->feed == c->stream)
3401 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3404 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3406 st->priv_data = NULL;
3408 /* build destination RTP address */
3409 ipaddr = inet_ntoa(dest_addr->sin_addr);
3411 switch(c->rtp_protocol) {
3412 case RTSP_LOWER_TRANSPORT_UDP:
3413 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3416 /* XXX: also pass as parameter to function ? */
3417 if (c->stream->is_multicast) {
3419 ttl = c->stream->multicast_ttl;
3422 snprintf(ctx->filename, sizeof(ctx->filename),
3423 "rtp://%s:%d?multicast=1&ttl=%d",
3424 ipaddr, ntohs(dest_addr->sin_port), ttl);
3426 snprintf(ctx->filename, sizeof(ctx->filename),
3427 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3430 if (url_open(&h, ctx->filename, AVIO_WRONLY) < 0)
3432 c->rtp_handles[stream_index] = h;
3433 max_packet_size = url_get_max_packet_size(h);
3435 case RTSP_LOWER_TRANSPORT_TCP:
3438 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3444 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3445 ipaddr, ntohs(dest_addr->sin_port),
3446 c->stream->filename, stream_index, c->protocol);
3448 /* normally, no packets should be output here, but the packet size may be checked */
3449 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3450 /* XXX: close stream */
3453 av_set_parameters(ctx, NULL);
3454 if (av_write_header(ctx) < 0) {
3461 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3464 c->rtp_ctx[stream_index] = ctx;
3468 /********************************************************************/
3469 /* ffserver initialization */
3471 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3475 fst = av_mallocz(sizeof(AVStream));
3479 fst->codec= avcodec_alloc_context();
3480 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3481 if (codec->extradata_size) {
3482 fst->codec->extradata = av_malloc(codec->extradata_size);
3483 memcpy(fst->codec->extradata, codec->extradata,
3484 codec->extradata_size);
3487 /* live streams must use the actual feed's codec since it may be
3488 * updated later to carry extradata needed by the streams.
3492 fst->priv_data = av_mallocz(sizeof(FeedData));
3493 fst->index = stream->nb_streams;
3494 av_set_pts_info(fst, 33, 1, 90000);
3495 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3496 stream->streams[stream->nb_streams++] = fst;
3500 /* return the stream number in the feed */
3501 static int add_av_stream(FFStream *feed, AVStream *st)
3504 AVCodecContext *av, *av1;
3508 for(i=0;i<feed->nb_streams;i++) {
3509 st = feed->streams[i];
3511 if (av1->codec_id == av->codec_id &&
3512 av1->codec_type == av->codec_type &&
3513 av1->bit_rate == av->bit_rate) {
3515 switch(av->codec_type) {
3516 case AVMEDIA_TYPE_AUDIO:
3517 if (av1->channels == av->channels &&
3518 av1->sample_rate == av->sample_rate)
3521 case AVMEDIA_TYPE_VIDEO:
3522 if (av1->width == av->width &&
3523 av1->height == av->height &&
3524 av1->time_base.den == av->time_base.den &&
3525 av1->time_base.num == av->time_base.num &&
3526 av1->gop_size == av->gop_size)
3535 fst = add_av_stream1(feed, av, 0);
3538 return feed->nb_streams - 1;
3543 static void remove_stream(FFStream *stream)
3547 while (*ps != NULL) {
3555 /* specific mpeg4 handling : we extract the raw parameters */
3556 static void extract_mpeg4_header(AVFormatContext *infile)
3558 int mpeg4_count, i, size;
3564 for(i=0;i<infile->nb_streams;i++) {
3565 st = infile->streams[i];
3566 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3567 st->codec->extradata_size == 0) {
3574 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3575 while (mpeg4_count > 0) {
3576 if (av_read_packet(infile, &pkt) < 0)
3578 st = infile->streams[pkt.stream_index];
3579 if (st->codec->codec_id == CODEC_ID_MPEG4 &&
3580 st->codec->extradata_size == 0) {
3581 av_freep(&st->codec->extradata);
3582 /* fill extradata with the header */
3583 /* XXX: we make hard suppositions here ! */
3585 while (p < pkt.data + pkt.size - 4) {
3586 /* stop when vop header is found */
3587 if (p[0] == 0x00 && p[1] == 0x00 &&
3588 p[2] == 0x01 && p[3] == 0xb6) {
3589 size = p - pkt.data;
3590 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3591 st->codec->extradata = av_malloc(size);
3592 st->codec->extradata_size = size;
3593 memcpy(st->codec->extradata, pkt.data, size);
3600 av_free_packet(&pkt);
3604 /* compute the needed AVStream for each file */
3605 static void build_file_streams(void)
3607 FFStream *stream, *stream_next;
3608 AVFormatContext *infile;
3611 /* gather all streams */
3612 for(stream = first_stream; stream != NULL; stream = stream_next) {
3613 stream_next = stream->next;
3614 if (stream->stream_type == STREAM_TYPE_LIVE &&
3616 /* the stream comes from a file */
3617 /* try to open the file */
3619 stream->ap_in = av_mallocz(sizeof(AVFormatParameters));
3620 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3621 /* specific case : if transport stream output to RTP,
3622 we use a raw transport stream reader */
3623 stream->ap_in->mpeg2ts_raw = 1;
3624 stream->ap_in->mpeg2ts_compute_pcr = 1;
3627 http_log("Opening file '%s'\n", stream->feed_filename);
3628 if ((ret = av_open_input_file(&infile, stream->feed_filename,
3629 stream->ifmt, 0, stream->ap_in)) < 0) {
3630 http_log("Could not open '%s': %d\n", stream->feed_filename, ret);
3631 /* remove stream (no need to spend more time on it) */
3633 remove_stream(stream);
3635 /* find all the AVStreams inside and reference them in
3637 if (av_find_stream_info(infile) < 0) {
3638 http_log("Could not find codec parameters from '%s'\n",
3639 stream->feed_filename);
3640 av_close_input_file(infile);
3643 extract_mpeg4_header(infile);
3645 for(i=0;i<infile->nb_streams;i++)
3646 add_av_stream1(stream, infile->streams[i]->codec, 1);
3648 av_close_input_file(infile);
3654 /* compute the needed AVStream for each feed */
3655 static void build_feed_streams(void)
3657 FFStream *stream, *feed;
3660 /* gather all streams */
3661 for(stream = first_stream; stream != NULL; stream = stream->next) {
3662 feed = stream->feed;
3664 if (!stream->is_feed) {
3665 /* we handle a stream coming from a feed */
3666 for(i=0;i<stream->nb_streams;i++)
3667 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3672 /* gather all streams */
3673 for(stream = first_stream; stream != NULL; stream = stream->next) {
3674 feed = stream->feed;
3676 if (stream->is_feed) {
3677 for(i=0;i<stream->nb_streams;i++)
3678 stream->feed_streams[i] = i;
3683 /* create feed files if needed */
3684 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3687 if (url_exist(feed->feed_filename)) {
3688 /* See if it matches */
3692 if (av_open_input_file(&s, feed->feed_filename, NULL, FFM_PACKET_SIZE, NULL) >= 0) {
3693 /* Now see if it matches */
3694 if (s->nb_streams == feed->nb_streams) {
3696 for(i=0;i<s->nb_streams;i++) {
3698 sf = feed->streams[i];
3701 if (sf->index != ss->index ||
3703 http_log("Index & Id do not match for stream %d (%s)\n",
3704 i, feed->feed_filename);
3707 AVCodecContext *ccf, *ccs;
3711 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3713 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3714 http_log("Codecs do not match for stream %d\n", i);
3716 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3717 http_log("Codec bitrates do not match for stream %d\n", i);
3719 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3720 if (CHECK_CODEC(time_base.den) ||
3721 CHECK_CODEC(time_base.num) ||
3722 CHECK_CODEC(width) ||
3723 CHECK_CODEC(height)) {
3724 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3727 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3728 if (CHECK_CODEC(sample_rate) ||
3729 CHECK_CODEC(channels) ||
3730 CHECK_CODEC(frame_size)) {
3731 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3735 http_log("Unknown codec type\n");
3743 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3744 feed->feed_filename, s->nb_streams, feed->nb_streams);
3746 av_close_input_file(s);
3748 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3749 feed->feed_filename);
3752 if (feed->readonly) {
3753 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3754 feed->feed_filename);
3757 unlink(feed->feed_filename);
3760 if (!url_exist(feed->feed_filename)) {
3761 AVFormatContext s1 = {0}, *s = &s1;
3763 if (feed->readonly) {
3764 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3765 feed->feed_filename);
3769 /* only write the header of the ffm file */
3770 if (avio_open(&s->pb, feed->feed_filename, AVIO_WRONLY) < 0) {
3771 http_log("Could not open output feed file '%s'\n",
3772 feed->feed_filename);
3775 s->oformat = feed->fmt;
3776 s->nb_streams = feed->nb_streams;
3777 for(i=0;i<s->nb_streams;i++) {
3779 st = feed->streams[i];
3782 av_set_parameters(s, NULL);
3783 if (av_write_header(s) < 0) {
3784 http_log("Container doesn't supports the required parameters\n");
3787 /* XXX: need better api */
3788 av_freep(&s->priv_data);
3791 /* get feed size and write index */
3792 fd = open(feed->feed_filename, O_RDONLY);
3794 http_log("Could not open output feed file '%s'\n",
3795 feed->feed_filename);
3799 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3800 feed->feed_size = lseek(fd, 0, SEEK_END);
3801 /* ensure that we do not wrap before the end of file */
3802 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3803 feed->feed_max_size = feed->feed_size;
3809 /* compute the bandwidth used by each stream */
3810 static void compute_bandwidth(void)
3816 for(stream = first_stream; stream != NULL; stream = stream->next) {
3818 for(i=0;i<stream->nb_streams;i++) {
3819 AVStream *st = stream->streams[i];
3820 switch(st->codec->codec_type) {
3821 case AVMEDIA_TYPE_AUDIO:
3822 case AVMEDIA_TYPE_VIDEO:
3823 bandwidth += st->codec->bit_rate;
3829 stream->bandwidth = (bandwidth + 999) / 1000;
3833 /* add a codec and set the default parameters */
3834 static void add_codec(FFStream *stream, AVCodecContext *av)
3838 /* compute default parameters */
3839 switch(av->codec_type) {
3840 case AVMEDIA_TYPE_AUDIO:
3841 if (av->bit_rate == 0)
3842 av->bit_rate = 64000;
3843 if (av->sample_rate == 0)
3844 av->sample_rate = 22050;
3845 if (av->channels == 0)
3848 case AVMEDIA_TYPE_VIDEO:
3849 if (av->bit_rate == 0)
3850 av->bit_rate = 64000;
3851 if (av->time_base.num == 0){
3852 av->time_base.den = 5;
3853 av->time_base.num = 1;
3855 if (av->width == 0 || av->height == 0) {
3859 /* Bitrate tolerance is less for streaming */
3860 if (av->bit_rate_tolerance == 0)
3861 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3862 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3867 if (av->max_qdiff == 0)
3869 av->qcompress = 0.5;
3872 if (!av->nsse_weight)
3873 av->nsse_weight = 8;
3875 av->frame_skip_cmp = FF_CMP_DCTMAX;
3877 av->me_method = ME_EPZS;
3878 av->rc_buffer_aggressivity = 1.0;
3881 av->rc_eq = "tex^qComp";
3882 if (!av->i_quant_factor)
3883 av->i_quant_factor = -0.8;
3884 if (!av->b_quant_factor)
3885 av->b_quant_factor = 1.25;
3886 if (!av->b_quant_offset)
3887 av->b_quant_offset = 1.25;
3888 if (!av->rc_max_rate)
3889 av->rc_max_rate = av->bit_rate * 2;
3891 if (av->rc_max_rate && !av->rc_buffer_size) {
3892 av->rc_buffer_size = av->rc_max_rate;
3901 st = av_mallocz(sizeof(AVStream));
3904 st->codec = avcodec_alloc_context();
3905 stream->streams[stream->nb_streams++] = st;
3906 memcpy(st->codec, av, sizeof(AVCodecContext));
3909 static enum CodecID opt_audio_codec(const char *arg)
3911 AVCodec *p= avcodec_find_encoder_by_name(arg);
3913 if (p == NULL || p->type != AVMEDIA_TYPE_AUDIO)
3914 return CODEC_ID_NONE;
3919 static enum CodecID opt_video_codec(const char *arg)
3921 AVCodec *p= avcodec_find_encoder_by_name(arg);
3923 if (p == NULL || p->type != AVMEDIA_TYPE_VIDEO)
3924 return CODEC_ID_NONE;
3929 /* simplistic plugin support */
3932 static void load_module(const char *filename)
3935 void (*init_func)(void);
3936 dll = dlopen(filename, RTLD_NOW);
3938 fprintf(stderr, "Could not load module '%s' - %s\n",
3939 filename, dlerror());
3943 init_func = dlsym(dll, "ffserver_module_init");
3946 "%s: init function 'ffserver_module_init()' not found\n",
3955 static int ffserver_opt_default(const char *opt, const char *arg,
3956 AVCodecContext *avctx, int type)
3959 const AVOption *o = av_find_opt(avctx, opt, NULL, type, type);
3961 ret = av_set_string3(avctx, opt, arg, 1, NULL);
3965 static int ffserver_opt_preset(const char *arg,
3966 AVCodecContext *avctx, int type,
3967 enum CodecID *audio_id, enum CodecID *video_id)
3970 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3972 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3974 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3975 codec ? codec->name : NULL))) {
3976 fprintf(stderr, "File for preset '%s' not found\n", arg);
3981 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3982 if(line[0] == '#' && !e)
3984 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3986 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3990 if(!strcmp(tmp, "acodec")){
3991 *audio_id = opt_audio_codec(tmp2);
3992 }else if(!strcmp(tmp, "vcodec")){
3993 *video_id = opt_video_codec(tmp2);
3994 }else if(!strcmp(tmp, "scodec")){
3995 /* opt_subtitle_codec(tmp2); */
3996 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3997 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4008 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4009 const char *mime_type)
4011 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4014 AVOutputFormat *stream_fmt;
4015 char stream_format_name[64];
4017 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4018 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4027 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4031 fprintf(stderr, "%s:%d: ", filename, line_num);
4032 vfprintf(stderr, fmt, vl);
4038 static int parse_ffconfig(const char *filename)
4045 int val, errors, line_num;
4046 FFStream **last_stream, *stream, *redirect;
4047 FFStream **last_feed, *feed, *s;
4048 AVCodecContext audio_enc, video_enc;
4049 enum CodecID audio_id, video_id;
4051 f = fopen(filename, "r");
4059 first_stream = NULL;
4060 last_stream = &first_stream;
4062 last_feed = &first_feed;
4066 audio_id = CODEC_ID_NONE;
4067 video_id = CODEC_ID_NONE;
4069 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4071 if (fgets(line, sizeof(line), f) == NULL)
4077 if (*p == '\0' || *p == '#')
4080 get_arg(cmd, sizeof(cmd), &p);
4082 if (!strcasecmp(cmd, "Port")) {
4083 get_arg(arg, sizeof(arg), &p);
4085 if (val < 1 || val > 65536) {
4086 ERROR("Invalid_port: %s\n", arg);
4088 my_http_addr.sin_port = htons(val);
4089 } else if (!strcasecmp(cmd, "BindAddress")) {
4090 get_arg(arg, sizeof(arg), &p);
4091 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4092 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4094 } else if (!strcasecmp(cmd, "NoDaemon")) {
4095 ffserver_daemon = 0;
4096 } else if (!strcasecmp(cmd, "RTSPPort")) {
4097 get_arg(arg, sizeof(arg), &p);
4099 if (val < 1 || val > 65536) {
4100 ERROR("%s:%d: Invalid port: %s\n", arg);
4102 my_rtsp_addr.sin_port = htons(atoi(arg));
4103 } else if (!strcasecmp(cmd, "RTSPBindAddress")) {
4104 get_arg(arg, sizeof(arg), &p);
4105 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4106 ERROR("Invalid host/IP address: %s\n", arg);
4108 } else if (!strcasecmp(cmd, "MaxHTTPConnections")) {
4109 get_arg(arg, sizeof(arg), &p);
4111 if (val < 1 || val > 65536) {
4112 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4114 nb_max_http_connections = val;
4115 } else if (!strcasecmp(cmd, "MaxClients")) {
4116 get_arg(arg, sizeof(arg), &p);
4118 if (val < 1 || val > nb_max_http_connections) {
4119 ERROR("Invalid MaxClients: %s\n", arg);
4121 nb_max_connections = val;
4123 } else if (!strcasecmp(cmd, "MaxBandwidth")) {
4125 get_arg(arg, sizeof(arg), &p);
4127 if (llval < 10 || llval > 10000000) {
4128 ERROR("Invalid MaxBandwidth: %s\n", arg);
4130 max_bandwidth = llval;
4131 } else if (!strcasecmp(cmd, "CustomLog")) {
4132 if (!ffserver_debug)
4133 get_arg(logfilename, sizeof(logfilename), &p);
4134 } else if (!strcasecmp(cmd, "<Feed")) {
4135 /*********************************************/
4136 /* Feed related options */
4138 if (stream || feed) {
4139 ERROR("Already in a tag\n");
4141 feed = av_mallocz(sizeof(FFStream));
4142 get_arg(feed->filename, sizeof(feed->filename), &p);
4143 q = strrchr(feed->filename, '>');
4147 for (s = first_feed; s; s = s->next) {
4148 if (!strcmp(feed->filename, s->filename)) {
4149 ERROR("Feed '%s' already registered\n", s->filename);
4153 feed->fmt = av_guess_format("ffm", NULL, NULL);
4154 /* defaut feed file */
4155 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4156 "/tmp/%s.ffm", feed->filename);
4157 feed->feed_max_size = 5 * 1024 * 1024;
4159 feed->feed = feed; /* self feeding :-) */
4161 /* add in stream list */
4162 *last_stream = feed;
4163 last_stream = &feed->next;
4164 /* add in feed list */
4166 last_feed = &feed->next_feed;
4168 } else if (!strcasecmp(cmd, "Launch")) {
4172 feed->child_argv = av_mallocz(64 * sizeof(char *));
4174 for (i = 0; i < 62; i++) {
4175 get_arg(arg, sizeof(arg), &p);
4179 feed->child_argv[i] = av_strdup(arg);
4182 feed->child_argv[i] = av_malloc(30 + strlen(feed->filename));
4184 snprintf(feed->child_argv[i], 30+strlen(feed->filename),
4186 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4187 inet_ntoa(my_http_addr.sin_addr),
4188 ntohs(my_http_addr.sin_port), feed->filename);
4190 } else if (!strcasecmp(cmd, "ReadOnlyFile")) {
4192 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4194 } else if (stream) {
4195 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4197 } else if (!strcasecmp(cmd, "File")) {
4199 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4201 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4202 } else if (!strcasecmp(cmd, "Truncate")) {
4204 get_arg(arg, sizeof(arg), &p);
4205 feed->truncate = strtod(arg, NULL);
4207 } else if (!strcasecmp(cmd, "FileMaxSize")) {
4212 get_arg(arg, sizeof(arg), &p);
4214 fsize = strtod(p1, &p1);
4215 switch(toupper(*p1)) {
4220 fsize *= 1024 * 1024;
4223 fsize *= 1024 * 1024 * 1024;
4226 feed->feed_max_size = (int64_t)fsize;
4227 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4228 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4231 } else if (!strcasecmp(cmd, "</Feed>")) {
4233 ERROR("No corresponding <Feed> for </Feed>\n");
4236 } else if (!strcasecmp(cmd, "<Stream")) {
4237 /*********************************************/
4238 /* Stream related options */
4240 if (stream || feed) {
4241 ERROR("Already in a tag\n");
4244 stream = av_mallocz(sizeof(FFStream));
4245 get_arg(stream->filename, sizeof(stream->filename), &p);
4246 q = strrchr(stream->filename, '>');
4250 for (s = first_stream; s; s = s->next) {
4251 if (!strcmp(stream->filename, s->filename)) {
4252 ERROR("Stream '%s' already registered\n", s->filename);
4256 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4257 avcodec_get_context_defaults2(&video_enc, AVMEDIA_TYPE_VIDEO);
4258 avcodec_get_context_defaults2(&audio_enc, AVMEDIA_TYPE_AUDIO);
4259 audio_id = CODEC_ID_NONE;
4260 video_id = CODEC_ID_NONE;
4262 audio_id = stream->fmt->audio_codec;
4263 video_id = stream->fmt->video_codec;
4266 *last_stream = stream;
4267 last_stream = &stream->next;
4269 } else if (!strcasecmp(cmd, "Feed")) {
4270 get_arg(arg, sizeof(arg), &p);
4275 while (sfeed != NULL) {
4276 if (!strcmp(sfeed->filename, arg))
4278 sfeed = sfeed->next_feed;
4281 ERROR("feed '%s' not defined\n", arg);
4283 stream->feed = sfeed;
4285 } else if (!strcasecmp(cmd, "Format")) {
4286 get_arg(arg, sizeof(arg), &p);
4288 if (!strcmp(arg, "status")) {
4289 stream->stream_type = STREAM_TYPE_STATUS;
4292 stream->stream_type = STREAM_TYPE_LIVE;
4293 /* jpeg cannot be used here, so use single frame jpeg */
4294 if (!strcmp(arg, "jpeg"))
4295 strcpy(arg, "mjpeg");
4296 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4298 ERROR("Unknown Format: %s\n", arg);
4302 audio_id = stream->fmt->audio_codec;
4303 video_id = stream->fmt->video_codec;
4306 } else if (!strcasecmp(cmd, "InputFormat")) {
4307 get_arg(arg, sizeof(arg), &p);
4309 stream->ifmt = av_find_input_format(arg);
4310 if (!stream->ifmt) {
4311 ERROR("Unknown input format: %s\n", arg);
4314 } else if (!strcasecmp(cmd, "FaviconURL")) {
4315 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4316 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4318 ERROR("FaviconURL only permitted for status streams\n");
4320 } else if (!strcasecmp(cmd, "Author")) {
4322 get_arg(stream->author, sizeof(stream->author), &p);
4323 } else if (!strcasecmp(cmd, "Comment")) {
4325 get_arg(stream->comment, sizeof(stream->comment), &p);
4326 } else if (!strcasecmp(cmd, "Copyright")) {
4328 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4329 } else if (!strcasecmp(cmd, "Title")) {
4331 get_arg(stream->title, sizeof(stream->title), &p);
4332 } else if (!strcasecmp(cmd, "Preroll")) {
4333 get_arg(arg, sizeof(arg), &p);
4335 stream->prebuffer = atof(arg) * 1000;
4336 } else if (!strcasecmp(cmd, "StartSendOnKey")) {
4338 stream->send_on_key = 1;
4339 } else if (!strcasecmp(cmd, "AudioCodec")) {
4340 get_arg(arg, sizeof(arg), &p);
4341 audio_id = opt_audio_codec(arg);
4342 if (audio_id == CODEC_ID_NONE) {
4343 ERROR("Unknown AudioCodec: %s\n", arg);
4345 } else if (!strcasecmp(cmd, "VideoCodec")) {
4346 get_arg(arg, sizeof(arg), &p);
4347 video_id = opt_video_codec(arg);
4348 if (video_id == CODEC_ID_NONE) {
4349 ERROR("Unknown VideoCodec: %s\n", arg);
4351 } else if (!strcasecmp(cmd, "MaxTime")) {
4352 get_arg(arg, sizeof(arg), &p);
4354 stream->max_time = atof(arg) * 1000;
4355 } else if (!strcasecmp(cmd, "AudioBitRate")) {
4356 get_arg(arg, sizeof(arg), &p);
4358 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4359 } else if (!strcasecmp(cmd, "AudioChannels")) {
4360 get_arg(arg, sizeof(arg), &p);
4362 audio_enc.channels = atoi(arg);
4363 } else if (!strcasecmp(cmd, "AudioSampleRate")) {
4364 get_arg(arg, sizeof(arg), &p);
4366 audio_enc.sample_rate = atoi(arg);
4367 } else if (!strcasecmp(cmd, "AudioQuality")) {
4368 get_arg(arg, sizeof(arg), &p);
4370 // audio_enc.quality = atof(arg) * 1000;
4372 } else if (!strcasecmp(cmd, "VideoBitRateRange")) {
4374 int minrate, maxrate;
4376 get_arg(arg, sizeof(arg), &p);
4378 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4379 video_enc.rc_min_rate = minrate * 1000;
4380 video_enc.rc_max_rate = maxrate * 1000;
4382 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4385 } else if (!strcasecmp(cmd, "Debug")) {
4387 get_arg(arg, sizeof(arg), &p);
4388 video_enc.debug = strtol(arg,0,0);
4390 } else if (!strcasecmp(cmd, "Strict")) {
4392 get_arg(arg, sizeof(arg), &p);
4393 video_enc.strict_std_compliance = atoi(arg);
4395 } else if (!strcasecmp(cmd, "VideoBufferSize")) {
4397 get_arg(arg, sizeof(arg), &p);
4398 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4400 } else if (!strcasecmp(cmd, "VideoBitRateTolerance")) {
4402 get_arg(arg, sizeof(arg), &p);
4403 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4405 } else if (!strcasecmp(cmd, "VideoBitRate")) {
4406 get_arg(arg, sizeof(arg), &p);
4408 video_enc.bit_rate = atoi(arg) * 1000;
4410 } else if (!strcasecmp(cmd, "VideoSize")) {
4411 get_arg(arg, sizeof(arg), &p);
4413 av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4414 if ((video_enc.width % 16) != 0 ||
4415 (video_enc.height % 16) != 0) {
4416 ERROR("Image size must be a multiple of 16\n");
4419 } else if (!strcasecmp(cmd, "VideoFrameRate")) {
4420 get_arg(arg, sizeof(arg), &p);
4422 AVRational frame_rate;
4423 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4424 ERROR("Incorrect frame rate: %s\n", arg);
4426 video_enc.time_base.num = frame_rate.den;
4427 video_enc.time_base.den = frame_rate.num;
4430 } else if (!strcasecmp(cmd, "VideoGopSize")) {
4431 get_arg(arg, sizeof(arg), &p);
4433 video_enc.gop_size = atoi(arg);
4434 } else if (!strcasecmp(cmd, "VideoIntraOnly")) {
4436 video_enc.gop_size = 1;
4437 } else if (!strcasecmp(cmd, "VideoHighQuality")) {
4439 video_enc.mb_decision = FF_MB_DECISION_BITS;
4440 } else if (!strcasecmp(cmd, "Video4MotionVector")) {
4442 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4443 video_enc.flags |= CODEC_FLAG_4MV;
4445 } else if (!strcasecmp(cmd, "AVOptionVideo") ||
4446 !strcasecmp(cmd, "AVOptionAudio")) {
4448 AVCodecContext *avctx;
4450 get_arg(arg, sizeof(arg), &p);
4451 get_arg(arg2, sizeof(arg2), &p);
4452 if (!strcasecmp(cmd, "AVOptionVideo")) {
4454 type = AV_OPT_FLAG_VIDEO_PARAM;
4457 type = AV_OPT_FLAG_AUDIO_PARAM;
4459 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4460 ERROR("AVOption error: %s %s\n", arg, arg2);
4462 } else if (!strcasecmp(cmd, "AVPresetVideo") ||
4463 !strcasecmp(cmd, "AVPresetAudio")) {
4464 AVCodecContext *avctx;
4466 get_arg(arg, sizeof(arg), &p);
4467 if (!strcasecmp(cmd, "AVPresetVideo")) {
4469 video_enc.codec_id = video_id;
4470 type = AV_OPT_FLAG_VIDEO_PARAM;
4473 audio_enc.codec_id = audio_id;
4474 type = AV_OPT_FLAG_AUDIO_PARAM;
4476 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4477 ERROR("AVPreset error: %s\n", arg);
4479 } else if (!strcasecmp(cmd, "VideoTag")) {
4480 get_arg(arg, sizeof(arg), &p);
4481 if ((strlen(arg) == 4) && stream)
4482 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4483 } else if (!strcasecmp(cmd, "BitExact")) {
4485 video_enc.flags |= CODEC_FLAG_BITEXACT;
4486 } else if (!strcasecmp(cmd, "DctFastint")) {
4488 video_enc.dct_algo = FF_DCT_FASTINT;
4489 } else if (!strcasecmp(cmd, "IdctSimple")) {
4491 video_enc.idct_algo = FF_IDCT_SIMPLE;
4492 } else if (!strcasecmp(cmd, "Qscale")) {
4493 get_arg(arg, sizeof(arg), &p);
4495 video_enc.flags |= CODEC_FLAG_QSCALE;
4496 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4498 } else if (!strcasecmp(cmd, "VideoQDiff")) {
4499 get_arg(arg, sizeof(arg), &p);
4501 video_enc.max_qdiff = atoi(arg);
4502 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4503 ERROR("VideoQDiff out of range\n");
4506 } else if (!strcasecmp(cmd, "VideoQMax")) {
4507 get_arg(arg, sizeof(arg), &p);
4509 video_enc.qmax = atoi(arg);
4510 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4511 ERROR("VideoQMax out of range\n");
4514 } else if (!strcasecmp(cmd, "VideoQMin")) {
4515 get_arg(arg, sizeof(arg), &p);
4517 video_enc.qmin = atoi(arg);
4518 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4519 ERROR("VideoQMin out of range\n");
4522 } else if (!strcasecmp(cmd, "LumaElim")) {
4523 get_arg(arg, sizeof(arg), &p);
4525 video_enc.luma_elim_threshold = atoi(arg);
4526 } else if (!strcasecmp(cmd, "ChromaElim")) {
4527 get_arg(arg, sizeof(arg), &p);
4529 video_enc.chroma_elim_threshold = atoi(arg);
4530 } else if (!strcasecmp(cmd, "LumiMask")) {
4531 get_arg(arg, sizeof(arg), &p);
4533 video_enc.lumi_masking = atof(arg);
4534 } else if (!strcasecmp(cmd, "DarkMask")) {
4535 get_arg(arg, sizeof(arg), &p);
4537 video_enc.dark_masking = atof(arg);
4538 } else if (!strcasecmp(cmd, "NoVideo")) {
4539 video_id = CODEC_ID_NONE;
4540 } else if (!strcasecmp(cmd, "NoAudio")) {
4541 audio_id = CODEC_ID_NONE;
4542 } else if (!strcasecmp(cmd, "ACL")) {
4543 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4544 } else if (!strcasecmp(cmd, "DynamicACL")) {
4546 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4548 } else if (!strcasecmp(cmd, "RTSPOption")) {
4549 get_arg(arg, sizeof(arg), &p);
4551 av_freep(&stream->rtsp_option);
4552 stream->rtsp_option = av_strdup(arg);
4554 } else if (!strcasecmp(cmd, "MulticastAddress")) {
4555 get_arg(arg, sizeof(arg), &p);
4557 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4558 ERROR("Invalid host/IP address: %s\n", arg);
4560 stream->is_multicast = 1;
4561 stream->loop = 1; /* default is looping */
4563 } else if (!strcasecmp(cmd, "MulticastPort")) {
4564 get_arg(arg, sizeof(arg), &p);
4566 stream->multicast_port = atoi(arg);
4567 } else if (!strcasecmp(cmd, "MulticastTTL")) {
4568 get_arg(arg, sizeof(arg), &p);
4570 stream->multicast_ttl = atoi(arg);
4571 } else if (!strcasecmp(cmd, "NoLoop")) {
4574 } else if (!strcasecmp(cmd, "</Stream>")) {
4576 ERROR("No corresponding <Stream> for </Stream>\n");
4578 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4579 if (audio_id != CODEC_ID_NONE) {
4580 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4581 audio_enc.codec_id = audio_id;
4582 add_codec(stream, &audio_enc);
4584 if (video_id != CODEC_ID_NONE) {
4585 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4586 video_enc.codec_id = video_id;
4587 add_codec(stream, &video_enc);
4592 } else if (!strcasecmp(cmd, "<Redirect")) {
4593 /*********************************************/
4595 if (stream || feed || redirect) {
4596 ERROR("Already in a tag\n");
4598 redirect = av_mallocz(sizeof(FFStream));
4599 *last_stream = redirect;
4600 last_stream = &redirect->next;
4602 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4603 q = strrchr(redirect->filename, '>');
4606 redirect->stream_type = STREAM_TYPE_REDIRECT;
4608 } else if (!strcasecmp(cmd, "URL")) {
4610 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4611 } else if (!strcasecmp(cmd, "</Redirect>")) {
4613 ERROR("No corresponding <Redirect> for </Redirect>\n");
4615 if (!redirect->feed_filename[0]) {
4616 ERROR("No URL found for <Redirect>\n");
4620 } else if (!strcasecmp(cmd, "LoadModule")) {
4621 get_arg(arg, sizeof(arg), &p);
4625 ERROR("Module support not compiled into this version: '%s'\n", arg);
4628 ERROR("Incorrect keyword: '%s'\n", cmd);
4640 static void handle_child_exit(int sig)
4645 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4648 for (feed = first_feed; feed; feed = feed->next) {
4649 if (feed->pid == pid) {
4650 int uptime = time(0) - feed->pid_start;
4653 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4656 /* Turn off any more restarts */
4657 feed->child_argv = 0;
4662 need_to_start_children = 1;
4665 static void opt_debug(void)
4668 ffserver_daemon = 0;
4669 logfilename[0] = '-';
4672 static void show_help(void)
4674 printf("usage: ffserver [options]\n"
4675 "Hyper fast multi format Audio/Video streaming server\n");
4677 show_help_options(options, "Main options:\n", 0, 0);
4680 static const OptionDef options[] = {
4681 #include "cmdutils_common_opts.h"
4682 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4683 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4684 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4688 int main(int argc, char **argv)
4690 struct sigaction sigact;
4696 my_program_name = argv[0];
4697 my_program_dir = getcwd(0, 0);
4698 ffserver_daemon = 1;
4700 parse_options(argc, argv, options, NULL);
4702 unsetenv("http_proxy"); /* Kill the http_proxy */
4704 av_lfg_init(&random_state, av_get_random_seed());
4706 memset(&sigact, 0, sizeof(sigact));
4707 sigact.sa_handler = handle_child_exit;
4708 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4709 sigaction(SIGCHLD, &sigact, 0);
4711 if (parse_ffconfig(config_filename) < 0) {
4712 fprintf(stderr, "Incorrect config file - exiting.\n");
4716 /* open log file if needed */
4717 if (logfilename[0] != '\0') {
4718 if (!strcmp(logfilename, "-"))
4721 logfile = fopen(logfilename, "a");
4722 av_log_set_callback(http_av_log);
4725 build_file_streams();
4727 build_feed_streams();
4729 compute_bandwidth();
4731 /* put the process in background and detach it from its TTY */
4732 if (ffserver_daemon) {
4739 } else if (pid > 0) {
4746 open("/dev/null", O_RDWR);
4747 if (strcmp(logfilename, "-") != 0) {
4757 signal(SIGPIPE, SIG_IGN);
4759 if (ffserver_daemon)
4762 if (http_server() < 0) {
4763 http_log("Could not start server\n");