2 * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * multiple format streaming server based on the FFmpeg libraries
28 #define closesocket close
33 #include "libavformat/avformat.h"
34 // FIXME those are internal headers, ffserver _really_ shouldn't use them
35 #include "libavformat/ffm.h"
36 #include "libavformat/network.h"
37 #include "libavformat/os_support.h"
38 #include "libavformat/rtpdec.h"
39 #include "libavformat/rtpproto.h"
40 #include "libavformat/rtsp.h"
41 #include "libavformat/avio_internal.h"
42 #include "libavformat/internal.h"
43 #include "libavformat/url.h"
45 #include "libavutil/avassert.h"
46 #include "libavutil/avstring.h"
47 #include "libavutil/lfg.h"
48 #include "libavutil/dict.h"
49 #include "libavutil/intreadwrite.h"
50 #include "libavutil/mathematics.h"
51 #include "libavutil/pixdesc.h"
52 #include "libavutil/random_seed.h"
53 #include "libavutil/parseutils.h"
54 #include "libavutil/opt.h"
55 #include "libavutil/time.h"
60 #include <sys/ioctl.h>
71 const char program_name[] = "ffserver";
72 const int program_birth_year = 2000;
74 static const OptionDef options[];
77 HTTPSTATE_WAIT_REQUEST,
78 HTTPSTATE_SEND_HEADER,
79 HTTPSTATE_SEND_DATA_HEADER,
80 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
81 HTTPSTATE_SEND_DATA_TRAILER,
82 HTTPSTATE_RECEIVE_DATA,
83 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
86 RTSPSTATE_WAIT_REQUEST,
88 RTSPSTATE_SEND_PACKET,
91 static const char *http_state[] = {
107 #define MAX_STREAMS 20
109 #define IOBUFFER_INIT_SIZE 8192
111 /* timeouts are in ms */
112 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
113 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
115 #define SYNC_TIMEOUT (10 * 1000)
117 typedef struct RTSPActionServerSetup {
119 char transport_option[512];
120 } RTSPActionServerSetup;
123 int64_t count1, count2;
124 int64_t time1, time2;
127 /* context associated with one connection */
128 typedef struct HTTPContext {
129 enum HTTPState state;
130 int fd; /* socket file descriptor */
131 struct sockaddr_in from_addr; /* origin */
132 struct pollfd *poll_entry; /* used when polling */
134 uint8_t *buffer_ptr, *buffer_end;
137 int chunked_encoding;
138 int chunk_size; /* 0 if it needs to be read */
139 struct HTTPContext *next;
140 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
144 /* input format handling */
145 AVFormatContext *fmt_in;
146 int64_t start_time; /* In milliseconds - this wraps fairly often */
147 int64_t first_pts; /* initial pts value */
148 int64_t cur_pts; /* current pts value from the stream in us */
149 int64_t cur_frame_duration; /* duration of the current frame in us */
150 int cur_frame_bytes; /* output frame size, needed to compute
151 the time at which we send each
153 int pts_stream_index; /* stream we choose as clock reference */
154 int64_t cur_clock; /* current clock reference value in us */
155 /* output format handling */
156 struct FFStream *stream;
157 /* -1 is invalid stream */
158 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
159 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
161 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
162 int last_packet_sent; /* true if last data packet was sent */
164 DataRateData datarate;
171 int is_packetized; /* if true, the stream is packetized */
172 int packet_stream_index; /* current stream for output in state machine */
174 /* RTSP state specific */
175 uint8_t *pb_buffer; /* XXX: use that in all the code */
177 int seq; /* RTSP sequence number */
179 /* RTP state specific */
180 enum RTSPLowerTransport rtp_protocol;
181 char session_id[32]; /* session id */
182 AVFormatContext *rtp_ctx[MAX_STREAMS];
184 /* RTP/UDP specific */
185 URLContext *rtp_handles[MAX_STREAMS];
187 /* RTP/TCP specific */
188 struct HTTPContext *rtsp_c;
189 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
192 /* each generated stream is described here */
196 STREAM_TYPE_REDIRECT,
199 enum IPAddressAction {
204 typedef struct IPAddressACL {
205 struct IPAddressACL *next;
206 enum IPAddressAction action;
207 /* These are in host order */
208 struct in_addr first;
212 /* description of each stream of the ffserver.conf file */
213 typedef struct FFStream {
214 enum StreamType stream_type;
215 char filename[1024]; /* stream filename */
216 struct FFStream *feed; /* feed we are using (can be null if
218 AVDictionary *in_opts; /* input parameters */
219 AVInputFormat *ifmt; /* if non NULL, force input format */
222 char dynamic_acl[1024];
224 int prebuffer; /* Number of millseconds early to start */
225 int64_t max_time; /* Number of milliseconds to run */
227 AVStream *streams[MAX_STREAMS];
228 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
229 char feed_filename[1024]; /* file name of the feed storage, or
230 input file name for a stream */
235 pid_t pid; /* Of ffmpeg process */
236 time_t pid_start; /* Of ffmpeg process */
238 struct FFStream *next;
239 unsigned bandwidth; /* bandwidth, in kbits/s */
242 /* multicast specific */
244 struct in_addr multicast_ip;
245 int multicast_port; /* first port used for multicast */
247 int loop; /* if true, send the stream in loops (only meaningful if file) */
250 int feed_opened; /* true if someone is writing to the feed */
251 int is_feed; /* true if it is a feed */
252 int readonly; /* True if writing is prohibited to the file */
253 int truncate; /* True if feeder connection truncate the feed file */
255 int64_t bytes_served;
256 int64_t feed_max_size; /* maximum storage size, zero means unlimited */
257 int64_t feed_write_index; /* current write position in feed (it wraps around) */
258 int64_t feed_size; /* current size of feed */
259 struct FFStream *next_feed;
262 typedef struct FeedData {
263 long long data_count;
264 float avg_frame_size; /* frame size averaged over last frames with exponential mean */
267 static struct sockaddr_in my_http_addr;
268 static struct sockaddr_in my_rtsp_addr;
270 static char logfilename[1024];
271 static HTTPContext *first_http_ctx;
272 static FFStream *first_feed; /* contains only feeds */
273 static FFStream *first_stream; /* contains all streams, including feeds */
275 static void new_connection(int server_fd, int is_rtsp);
276 static void close_connection(HTTPContext *c);
279 static int handle_connection(HTTPContext *c);
280 static int http_parse_request(HTTPContext *c);
281 static int http_send_data(HTTPContext *c);
282 static void compute_status(HTTPContext *c);
283 static int open_input_stream(HTTPContext *c, const char *info);
284 static int http_start_receive_data(HTTPContext *c);
285 static int http_receive_data(HTTPContext *c);
288 static int rtsp_parse_request(HTTPContext *c);
289 static void rtsp_cmd_describe(HTTPContext *c, const char *url);
290 static void rtsp_cmd_options(HTTPContext *c, const char *url);
291 static void rtsp_cmd_setup(HTTPContext *c, const char *url, RTSPMessageHeader *h);
292 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h);
293 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h);
294 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h);
297 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
298 struct in_addr my_ip);
301 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
302 FFStream *stream, const char *session_id,
303 enum RTSPLowerTransport rtp_protocol);
304 static int rtp_new_av_stream(HTTPContext *c,
305 int stream_index, struct sockaddr_in *dest_addr,
306 HTTPContext *rtsp_c);
308 static const char *my_program_name;
310 static const char *config_filename;
312 static int ffserver_debug;
313 static int no_launch;
314 static int need_to_start_children;
316 /* maximum number of simultaneous HTTP connections */
317 static unsigned int nb_max_http_connections = 2000;
318 static unsigned int nb_max_connections = 5;
319 static unsigned int nb_connections;
321 static uint64_t max_bandwidth = 1000;
322 static uint64_t current_bandwidth;
324 static int64_t cur_time; // Making this global saves on passing it around everywhere
326 static AVLFG random_state;
328 static FILE *logfile = NULL;
330 static void htmlstrip(char *s) {
332 s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
338 static int64_t ffm_read_write_index(int fd)
342 if (lseek(fd, 8, SEEK_SET) < 0)
344 if (read(fd, buf, 8) != 8)
349 static int ffm_write_write_index(int fd, int64_t pos)
355 buf[i] = (pos >> (56 - i * 8)) & 0xff;
356 if (lseek(fd, 8, SEEK_SET) < 0)
358 if (write(fd, buf, 8) != 8)
363 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
366 FFMContext *ffm = s->priv_data;
367 ffm->write_index = pos;
368 ffm->file_size = file_size;
371 /* FIXME: make ffserver work with IPv6 */
372 /* resolve host with also IP address parsing */
373 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
376 if (!ff_inet_aton(hostname, sin_addr)) {
378 struct addrinfo *ai, *cur;
379 struct addrinfo hints = { 0 };
380 hints.ai_family = AF_INET;
381 if (getaddrinfo(hostname, NULL, &hints, &ai))
383 /* getaddrinfo returns a linked list of addrinfo structs.
384 * Even if we set ai_family = AF_INET above, make sure
385 * that the returned one actually is of the correct type. */
386 for (cur = ai; cur; cur = cur->ai_next) {
387 if (cur->ai_family == AF_INET) {
388 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
397 hp = gethostbyname(hostname);
400 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
406 static char *ctime1(char *buf2, int buf_size)
413 av_strlcpy(buf2, p, buf_size);
414 p = buf2 + strlen(p) - 1;
420 static void http_vlog(const char *fmt, va_list vargs)
422 static int print_prefix = 1;
426 ctime1(buf, sizeof(buf));
427 fprintf(logfile, "%s ", buf);
429 print_prefix = strstr(fmt, "\n") != NULL;
430 vfprintf(logfile, fmt, vargs);
436 __attribute__ ((format (printf, 1, 2)))
438 static void http_log(const char *fmt, ...)
441 va_start(vargs, fmt);
442 http_vlog(fmt, vargs);
446 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
448 static int print_prefix = 1;
449 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
450 if (level > av_log_get_level())
452 if (print_prefix && avc)
453 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
454 print_prefix = strstr(fmt, "\n") != NULL;
455 http_vlog(fmt, vargs);
458 static void log_connection(HTTPContext *c)
463 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
464 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
465 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
468 static void update_datarate(DataRateData *drd, int64_t count)
470 if (!drd->time1 && !drd->count1) {
471 drd->time1 = drd->time2 = cur_time;
472 drd->count1 = drd->count2 = count;
473 } else if (cur_time - drd->time2 > 5000) {
474 drd->time1 = drd->time2;
475 drd->count1 = drd->count2;
476 drd->time2 = cur_time;
481 /* In bytes per second */
482 static int compute_datarate(DataRateData *drd, int64_t count)
484 if (cur_time == drd->time1)
487 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
491 static void start_children(FFStream *feed)
496 for (; feed; feed = feed->next) {
497 if (feed->child_argv && !feed->pid) {
498 feed->pid_start = time(0);
503 http_log("Unable to create children\n");
512 /* replace "ffserver" with "ffmpeg" in the path of current program,
513 * ignore user provided path */
514 av_strlcpy(pathname, my_program_name, sizeof(pathname));
515 slash = strrchr(pathname, '/');
520 strcpy(slash, "ffmpeg");
522 http_log("Launch command line: ");
523 http_log("%s ", pathname);
524 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
525 http_log("%s ", feed->child_argv[i]);
528 for (i = 3; i < 256; i++)
531 if (!ffserver_debug) {
532 if (!freopen("/dev/null", "r", stdin))
533 http_log("failed to redirect STDIN to /dev/null\n;");
534 if (!freopen("/dev/null", "w", stdout))
535 http_log("failed to redirect STDOUT to /dev/null\n;");
536 if (!freopen("/dev/null", "w", stderr))
537 http_log("failed to redirect STDERR to /dev/null\n;");
540 signal(SIGPIPE, SIG_DFL);
542 execvp(pathname, feed->child_argv);
550 /* open a listening socket */
551 static int socket_open_listen(struct sockaddr_in *my_addr)
555 server_fd = socket(AF_INET,SOCK_STREAM,0);
562 setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp));
564 my_addr->sin_family = AF_INET;
565 if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) {
567 snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", ntohs(my_addr->sin_port));
569 closesocket(server_fd);
573 if (listen (server_fd, 5) < 0) {
575 closesocket(server_fd);
578 ff_socket_nonblock(server_fd, 1);
583 /* start all multicast streams */
584 static void start_multicast(void)
589 struct sockaddr_in dest_addr = {0};
590 int default_port, stream_index;
593 for(stream = first_stream; stream != NULL; stream = stream->next) {
594 if (stream->is_multicast) {
595 unsigned random0 = av_lfg_get(&random_state);
596 unsigned random1 = av_lfg_get(&random_state);
597 /* open the RTP connection */
598 snprintf(session_id, sizeof(session_id), "%08x%08x",
601 /* choose a port if none given */
602 if (stream->multicast_port == 0) {
603 stream->multicast_port = default_port;
607 dest_addr.sin_family = AF_INET;
608 dest_addr.sin_addr = stream->multicast_ip;
609 dest_addr.sin_port = htons(stream->multicast_port);
611 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
612 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
616 if (open_input_stream(rtp_c, "") < 0) {
617 http_log("Could not open input stream for stream '%s'\n",
622 /* open each RTP stream */
623 for(stream_index = 0; stream_index < stream->nb_streams;
625 dest_addr.sin_port = htons(stream->multicast_port +
627 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
628 http_log("Could not open output stream '%s/streamid=%d'\n",
629 stream->filename, stream_index);
634 /* change state to send data */
635 rtp_c->state = HTTPSTATE_SEND_DATA;
640 /* main loop of the http server */
641 static int http_server(void)
643 int server_fd = 0, rtsp_server_fd = 0;
644 int ret, delay, delay1;
645 struct pollfd *poll_table, *poll_entry;
646 HTTPContext *c, *c_next;
648 if(!(poll_table = av_mallocz((nb_max_http_connections + 2)*sizeof(*poll_table)))) {
649 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
653 if (my_http_addr.sin_port) {
654 server_fd = socket_open_listen(&my_http_addr);
659 if (my_rtsp_addr.sin_port) {
660 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
661 if (rtsp_server_fd < 0)
665 if (!rtsp_server_fd && !server_fd) {
666 http_log("HTTP and RTSP disabled.\n");
670 http_log("FFserver started.\n");
672 start_children(first_feed);
677 poll_entry = poll_table;
679 poll_entry->fd = server_fd;
680 poll_entry->events = POLLIN;
683 if (rtsp_server_fd) {
684 poll_entry->fd = rtsp_server_fd;
685 poll_entry->events = POLLIN;
689 /* wait for events on each HTTP handle */
696 case HTTPSTATE_SEND_HEADER:
697 case RTSPSTATE_SEND_REPLY:
698 case RTSPSTATE_SEND_PACKET:
699 c->poll_entry = poll_entry;
701 poll_entry->events = POLLOUT;
704 case HTTPSTATE_SEND_DATA_HEADER:
705 case HTTPSTATE_SEND_DATA:
706 case HTTPSTATE_SEND_DATA_TRAILER:
707 if (!c->is_packetized) {
708 /* for TCP, we output as much as we can (may need to put a limit) */
709 c->poll_entry = poll_entry;
711 poll_entry->events = POLLOUT;
714 /* when ffserver is doing the timing, we work by
715 looking at which packet need to be sent every
717 delay1 = 10; /* one tick wait XXX: 10 ms assumed */
722 case HTTPSTATE_WAIT_REQUEST:
723 case HTTPSTATE_RECEIVE_DATA:
724 case HTTPSTATE_WAIT_FEED:
725 case RTSPSTATE_WAIT_REQUEST:
726 /* need to catch errors */
727 c->poll_entry = poll_entry;
729 poll_entry->events = POLLIN;/* Maybe this will work */
733 c->poll_entry = NULL;
739 /* wait for an event on one connection. We poll at least every
740 second to handle timeouts */
742 ret = poll(poll_table, poll_entry - poll_table, delay);
743 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
744 ff_neterrno() != AVERROR(EINTR))
748 cur_time = av_gettime() / 1000;
750 if (need_to_start_children) {
751 need_to_start_children = 0;
752 start_children(first_feed);
755 /* now handle the events */
756 for(c = first_http_ctx; c != NULL; c = c_next) {
758 if (handle_connection(c) < 0) {
759 /* close and free the connection */
765 poll_entry = poll_table;
767 /* new HTTP connection request ? */
768 if (poll_entry->revents & POLLIN)
769 new_connection(server_fd, 0);
772 if (rtsp_server_fd) {
773 /* new RTSP connection request ? */
774 if (poll_entry->revents & POLLIN)
775 new_connection(rtsp_server_fd, 1);
780 /* start waiting for a new HTTP/RTSP request */
781 static void start_wait_request(HTTPContext *c, int is_rtsp)
783 c->buffer_ptr = c->buffer;
784 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
787 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
788 c->state = RTSPSTATE_WAIT_REQUEST;
790 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
791 c->state = HTTPSTATE_WAIT_REQUEST;
795 static void http_send_too_busy_reply(int fd)
798 int len = snprintf(buffer, sizeof(buffer),
799 "HTTP/1.0 503 Server too busy\r\n"
800 "Content-type: text/html\r\n"
802 "<html><head><title>Too busy</title></head><body>\r\n"
803 "<p>The server is too busy to serve your request at this time.</p>\r\n"
804 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
805 "</body></html>\r\n",
806 nb_connections, nb_max_connections);
807 av_assert0(len < sizeof(buffer));
808 send(fd, buffer, len, 0);
812 static void new_connection(int server_fd, int is_rtsp)
814 struct sockaddr_in from_addr;
817 HTTPContext *c = NULL;
819 len = sizeof(from_addr);
820 fd = accept(server_fd, (struct sockaddr *)&from_addr,
823 http_log("error during accept %s\n", strerror(errno));
826 ff_socket_nonblock(fd, 1);
828 if (nb_connections >= nb_max_connections) {
829 http_send_too_busy_reply(fd);
833 /* add a new connection */
834 c = av_mallocz(sizeof(HTTPContext));
839 c->poll_entry = NULL;
840 c->from_addr = from_addr;
841 c->buffer_size = IOBUFFER_INIT_SIZE;
842 c->buffer = av_malloc(c->buffer_size);
846 c->next = first_http_ctx;
850 start_wait_request(c, is_rtsp);
862 static void close_connection(HTTPContext *c)
864 HTTPContext **cp, *c1;
866 AVFormatContext *ctx;
870 /* remove connection from list */
871 cp = &first_http_ctx;
872 while ((*cp) != NULL) {
880 /* remove references, if any (XXX: do it faster) */
881 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
886 /* remove connection associated resources */
890 /* close each frame parser */
891 for(i=0;i<c->fmt_in->nb_streams;i++) {
892 st = c->fmt_in->streams[i];
893 if (st->codec->codec)
894 avcodec_close(st->codec);
896 avformat_close_input(&c->fmt_in);
899 /* free RTP output streams if any */
902 nb_streams = c->stream->nb_streams;
904 for(i=0;i<nb_streams;i++) {
907 av_write_trailer(ctx);
908 av_dict_free(&ctx->metadata);
909 av_free(ctx->streams[0]);
912 h = c->rtp_handles[i];
919 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
922 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
923 av_write_trailer(ctx);
924 av_freep(&c->pb_buffer);
925 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
930 for(i=0; i<ctx->nb_streams; i++)
931 av_free(ctx->streams[i]);
932 av_freep(&ctx->streams);
933 av_freep(&ctx->priv_data);
935 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
936 current_bandwidth -= c->stream->bandwidth;
938 /* signal that there is no feed if we are the feeder socket */
939 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
940 c->stream->feed_opened = 0;
944 av_freep(&c->pb_buffer);
945 av_freep(&c->packet_buffer);
951 static int handle_connection(HTTPContext *c)
956 case HTTPSTATE_WAIT_REQUEST:
957 case RTSPSTATE_WAIT_REQUEST:
959 if ((c->timeout - cur_time) < 0)
961 if (c->poll_entry->revents & (POLLERR | POLLHUP))
964 /* no need to read if no events */
965 if (!(c->poll_entry->revents & POLLIN))
969 len = recv(c->fd, c->buffer_ptr, 1, 0);
971 if (ff_neterrno() != AVERROR(EAGAIN) &&
972 ff_neterrno() != AVERROR(EINTR))
974 } else if (len == 0) {
977 /* search for end of request. */
979 c->buffer_ptr += len;
981 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
982 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
983 /* request found : parse it and reply */
984 if (c->state == HTTPSTATE_WAIT_REQUEST) {
985 ret = http_parse_request(c);
987 ret = rtsp_parse_request(c);
991 } else if (ptr >= c->buffer_end) {
992 /* request too long: cannot do anything */
994 } else goto read_loop;
998 case HTTPSTATE_SEND_HEADER:
999 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1002 /* no need to write if no events */
1003 if (!(c->poll_entry->revents & POLLOUT))
1005 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1007 if (ff_neterrno() != AVERROR(EAGAIN) &&
1008 ff_neterrno() != AVERROR(EINTR)) {
1009 /* error : close connection */
1010 av_freep(&c->pb_buffer);
1014 c->buffer_ptr += len;
1016 c->stream->bytes_served += len;
1017 c->data_count += len;
1018 if (c->buffer_ptr >= c->buffer_end) {
1019 av_freep(&c->pb_buffer);
1020 /* if error, exit */
1023 /* all the buffer was sent : synchronize to the incoming stream */
1024 c->state = HTTPSTATE_SEND_DATA_HEADER;
1025 c->buffer_ptr = c->buffer_end = c->buffer;
1030 case HTTPSTATE_SEND_DATA:
1031 case HTTPSTATE_SEND_DATA_HEADER:
1032 case HTTPSTATE_SEND_DATA_TRAILER:
1033 /* for packetized output, we consider we can always write (the
1034 input streams sets the speed). It may be better to verify
1035 that we do not rely too much on the kernel queues */
1036 if (!c->is_packetized) {
1037 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1040 /* no need to read if no events */
1041 if (!(c->poll_entry->revents & POLLOUT))
1044 if (http_send_data(c) < 0)
1046 /* close connection if trailer sent */
1047 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1050 case HTTPSTATE_RECEIVE_DATA:
1051 /* no need to read if no events */
1052 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1054 if (!(c->poll_entry->revents & POLLIN))
1056 if (http_receive_data(c) < 0)
1059 case HTTPSTATE_WAIT_FEED:
1060 /* no need to read if no events */
1061 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1064 /* nothing to do, we'll be waken up by incoming feed packets */
1067 case RTSPSTATE_SEND_REPLY:
1068 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1069 av_freep(&c->pb_buffer);
1072 /* no need to write if no events */
1073 if (!(c->poll_entry->revents & POLLOUT))
1075 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1077 if (ff_neterrno() != AVERROR(EAGAIN) &&
1078 ff_neterrno() != AVERROR(EINTR)) {
1079 /* error : close connection */
1080 av_freep(&c->pb_buffer);
1084 c->buffer_ptr += len;
1085 c->data_count += len;
1086 if (c->buffer_ptr >= c->buffer_end) {
1087 /* all the buffer was sent : wait for a new request */
1088 av_freep(&c->pb_buffer);
1089 start_wait_request(c, 1);
1093 case RTSPSTATE_SEND_PACKET:
1094 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1095 av_freep(&c->packet_buffer);
1098 /* no need to write if no events */
1099 if (!(c->poll_entry->revents & POLLOUT))
1101 len = send(c->fd, c->packet_buffer_ptr,
1102 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1104 if (ff_neterrno() != AVERROR(EAGAIN) &&
1105 ff_neterrno() != AVERROR(EINTR)) {
1106 /* error : close connection */
1107 av_freep(&c->packet_buffer);
1111 c->packet_buffer_ptr += len;
1112 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1113 /* all the buffer was sent : wait for a new request */
1114 av_freep(&c->packet_buffer);
1115 c->state = RTSPSTATE_WAIT_REQUEST;
1119 case HTTPSTATE_READY:
1128 static int extract_rates(char *rates, int ratelen, const char *request)
1132 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1133 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1134 const char *q = p + 7;
1136 while (*q && *q != '\n' && av_isspace(*q))
1139 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1145 memset(rates, 0xff, ratelen);
1148 while (*q && *q != '\n' && *q != ':')
1151 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1155 if (stream_no < ratelen && stream_no >= 0)
1156 rates[stream_no] = rate_no;
1158 while (*q && *q != '\n' && !av_isspace(*q))
1165 p = strchr(p, '\n');
1175 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1178 int best_bitrate = 100000000;
1181 for (i = 0; i < feed->nb_streams; i++) {
1182 AVCodecContext *feed_codec = feed->streams[i]->codec;
1184 if (feed_codec->codec_id != codec->codec_id ||
1185 feed_codec->sample_rate != codec->sample_rate ||
1186 feed_codec->width != codec->width ||
1187 feed_codec->height != codec->height)
1190 /* Potential stream */
1192 /* We want the fastest stream less than bit_rate, or the slowest
1193 * faster than bit_rate
1196 if (feed_codec->bit_rate <= bit_rate) {
1197 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1198 best_bitrate = feed_codec->bit_rate;
1202 if (feed_codec->bit_rate < best_bitrate) {
1203 best_bitrate = feed_codec->bit_rate;
1212 static int modify_current_stream(HTTPContext *c, char *rates)
1215 FFStream *req = c->stream;
1216 int action_required = 0;
1218 /* Not much we can do for a feed */
1222 for (i = 0; i < req->nb_streams; i++) {
1223 AVCodecContext *codec = req->streams[i]->codec;
1227 c->switch_feed_streams[i] = req->feed_streams[i];
1230 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1233 /* Wants off or slow */
1234 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1236 /* This doesn't work well when it turns off the only stream! */
1237 c->switch_feed_streams[i] = -2;
1238 c->feed_streams[i] = -2;
1243 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1244 action_required = 1;
1247 return action_required;
1250 /* XXX: factorize in utils.c ? */
1251 /* XXX: take care with different space meaning */
1252 static void skip_spaces(const char **pp)
1256 while (*p == ' ' || *p == '\t')
1261 static void get_word(char *buf, int buf_size, const char **pp)
1269 while (!av_isspace(*p) && *p != '\0') {
1270 if ((q - buf) < buf_size - 1)
1279 static void get_arg(char *buf, int buf_size, const char **pp)
1286 while (av_isspace(*p)) p++;
1289 if (*p == '\"' || *p == '\'')
1301 if ((q - buf) < buf_size - 1)
1306 if (quote && *p == quote)
1311 static void parse_acl_row(FFStream *stream, FFStream* feed, IPAddressACL *ext_acl,
1312 const char *p, const char *filename, int line_num)
1318 get_arg(arg, sizeof(arg), &p);
1319 if (av_strcasecmp(arg, "allow") == 0)
1320 acl.action = IP_ALLOW;
1321 else if (av_strcasecmp(arg, "deny") == 0)
1322 acl.action = IP_DENY;
1324 fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n",
1325 filename, line_num, arg);
1329 get_arg(arg, sizeof(arg), &p);
1331 if (resolve_host(&acl.first, arg) != 0) {
1332 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1333 filename, line_num, arg);
1336 acl.last = acl.first;
1338 get_arg(arg, sizeof(arg), &p);
1341 if (resolve_host(&acl.last, arg) != 0) {
1342 fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n",
1343 filename, line_num, arg);
1349 IPAddressACL *nacl = av_mallocz(sizeof(*nacl));
1350 IPAddressACL **naclp = 0;
1356 naclp = &stream->acl;
1362 fprintf(stderr, "%s:%d: ACL found not in <stream> or <feed>\n",
1363 filename, line_num);
1369 naclp = &(*naclp)->next;
1377 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1382 IPAddressACL *acl = NULL;
1386 f = fopen(stream->dynamic_acl, "r");
1388 perror(stream->dynamic_acl);
1392 acl = av_mallocz(sizeof(IPAddressACL));
1396 if (fgets(line, sizeof(line), f) == NULL)
1400 while (av_isspace(*p))
1402 if (*p == '\0' || *p == '#')
1404 get_arg(cmd, sizeof(cmd), &p);
1406 if (!av_strcasecmp(cmd, "ACL"))
1407 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1414 static void free_acl_list(IPAddressACL *in_acl)
1416 IPAddressACL *pacl,*pacl2;
1426 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1428 enum IPAddressAction last_action = IP_DENY;
1430 struct in_addr *src = &c->from_addr.sin_addr;
1431 unsigned long src_addr = src->s_addr;
1433 for (acl = in_acl; acl; acl = acl->next) {
1434 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1435 return (acl->action == IP_ALLOW) ? 1 : 0;
1436 last_action = acl->action;
1439 /* Nothing matched, so return not the last action */
1440 return (last_action == IP_DENY) ? 1 : 0;
1443 static int validate_acl(FFStream *stream, HTTPContext *c)
1449 /* if stream->acl is null validate_acl_list will return 1 */
1450 ret = validate_acl_list(stream->acl, c);
1452 if (stream->dynamic_acl[0]) {
1453 acl = parse_dynamic_acl(stream, c);
1455 ret = validate_acl_list(acl, c);
1463 /* compute the real filename of a file by matching it without its
1464 extensions to all the stream filenames */
1465 static void compute_real_filename(char *filename, int max_size)
1472 /* compute filename by matching without the file extensions */
1473 av_strlcpy(file1, filename, sizeof(file1));
1474 p = strrchr(file1, '.');
1477 for(stream = first_stream; stream != NULL; stream = stream->next) {
1478 av_strlcpy(file2, stream->filename, sizeof(file2));
1479 p = strrchr(file2, '.');
1482 if (!strcmp(file1, file2)) {
1483 av_strlcpy(filename, stream->filename, max_size);
1498 /* parse http request and prepare header */
1499 static int http_parse_request(HTTPContext *c)
1503 enum RedirType redir_type;
1505 char info[1024], filename[1024];
1509 const char *mime_type;
1513 const char *useragent = 0;
1516 get_word(cmd, sizeof(cmd), &p);
1517 av_strlcpy(c->method, cmd, sizeof(c->method));
1519 if (!strcmp(cmd, "GET"))
1521 else if (!strcmp(cmd, "POST"))
1526 get_word(url, sizeof(url), &p);
1527 av_strlcpy(c->url, url, sizeof(c->url));
1529 get_word(protocol, sizeof(protocol), (const char **)&p);
1530 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1533 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1536 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1538 /* find the filename and the optional info string in the request */
1539 p1 = strchr(url, '?');
1541 av_strlcpy(info, p1, sizeof(info));
1546 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1548 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1549 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1551 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1555 p = strchr(p, '\n');
1562 redir_type = REDIR_NONE;
1563 if (av_match_ext(filename, "asx")) {
1564 redir_type = REDIR_ASX;
1565 filename[strlen(filename)-1] = 'f';
1566 } else if (av_match_ext(filename, "asf") &&
1567 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1568 /* if this isn't WMP or lookalike, return the redirector file */
1569 redir_type = REDIR_ASF;
1570 } else if (av_match_ext(filename, "rpm,ram")) {
1571 redir_type = REDIR_RAM;
1572 strcpy(filename + strlen(filename)-2, "m");
1573 } else if (av_match_ext(filename, "rtsp")) {
1574 redir_type = REDIR_RTSP;
1575 compute_real_filename(filename, sizeof(filename) - 1);
1576 } else if (av_match_ext(filename, "sdp")) {
1577 redir_type = REDIR_SDP;
1578 compute_real_filename(filename, sizeof(filename) - 1);
1581 // "redirect" / request to index.html
1582 if (!strlen(filename))
1583 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1585 stream = first_stream;
1586 while (stream != NULL) {
1587 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1589 stream = stream->next;
1591 if (stream == NULL) {
1592 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1593 http_log("File '%s' not found\n", url);
1598 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1599 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1601 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1602 c->http_error = 301;
1604 snprintf(q, c->buffer_size,
1605 "HTTP/1.0 301 Moved\r\n"
1607 "Content-type: text/html\r\n"
1609 "<html><head><title>Moved</title></head><body>\r\n"
1610 "You should be <a href=\"%s\">redirected</a>.\r\n"
1611 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1613 /* prepare output buffer */
1614 c->buffer_ptr = c->buffer;
1616 c->state = HTTPSTATE_SEND_HEADER;
1620 /* If this is WMP, get the rate information */
1621 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1622 if (modify_current_stream(c, ratebuf)) {
1623 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1624 if (c->switch_feed_streams[i] >= 0)
1625 c->switch_feed_streams[i] = -1;
1630 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1631 current_bandwidth += stream->bandwidth;
1633 /* If already streaming this feed, do not let start another feeder. */
1634 if (stream->feed_opened) {
1635 snprintf(msg, sizeof(msg), "This feed is already being received.");
1636 http_log("Feed '%s' already being received\n", stream->feed_filename);
1640 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1641 c->http_error = 503;
1643 snprintf(q, c->buffer_size,
1644 "HTTP/1.0 503 Server too busy\r\n"
1645 "Content-type: text/html\r\n"
1647 "<html><head><title>Too busy</title></head><body>\r\n"
1648 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1649 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1650 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1651 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1653 /* prepare output buffer */
1654 c->buffer_ptr = c->buffer;
1656 c->state = HTTPSTATE_SEND_HEADER;
1660 if (redir_type != REDIR_NONE) {
1661 const char *hostinfo = 0;
1663 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1664 if (av_strncasecmp(p, "Host:", 5) == 0) {
1668 p = strchr(p, '\n');
1679 while (av_isspace(*hostinfo))
1682 eoh = strchr(hostinfo, '\n');
1684 if (eoh[-1] == '\r')
1687 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1688 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1689 hostbuf[eoh - hostinfo] = 0;
1691 c->http_error = 200;
1693 switch(redir_type) {
1695 snprintf(q, c->buffer_size,
1696 "HTTP/1.0 200 ASX Follows\r\n"
1697 "Content-type: video/x-ms-asf\r\n"
1699 "<ASX Version=\"3\">\r\n"
1700 //"<!-- Autogenerated by ffserver -->\r\n"
1701 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1702 "</ASX>\r\n", hostbuf, filename, info);
1706 snprintf(q, c->buffer_size,
1707 "HTTP/1.0 200 RAM Follows\r\n"
1708 "Content-type: audio/x-pn-realaudio\r\n"
1710 "# Autogenerated by ffserver\r\n"
1711 "http://%s/%s%s\r\n", hostbuf, filename, info);
1715 snprintf(q, c->buffer_size,
1716 "HTTP/1.0 200 ASF Redirect follows\r\n"
1717 "Content-type: video/x-ms-asf\r\n"
1720 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1725 char hostname[256], *p;
1726 /* extract only hostname */
1727 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1728 p = strrchr(hostname, ':');
1731 snprintf(q, c->buffer_size,
1732 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1733 /* XXX: incorrect mime type ? */
1734 "Content-type: application/x-rtsp\r\n"
1736 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1745 struct sockaddr_in my_addr;
1747 snprintf(q, c->buffer_size,
1748 "HTTP/1.0 200 OK\r\n"
1749 "Content-type: application/sdp\r\n"
1753 len = sizeof(my_addr);
1754 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
1756 /* XXX: should use a dynamic buffer */
1757 sdp_data_size = prepare_sdp_description(stream,
1760 if (sdp_data_size > 0) {
1761 memcpy(q, sdp_data, sdp_data_size);
1773 /* prepare output buffer */
1774 c->buffer_ptr = c->buffer;
1776 c->state = HTTPSTATE_SEND_HEADER;
1782 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1786 stream->conns_served++;
1788 /* XXX: add there authenticate and IP match */
1791 /* if post, it means a feed is being sent */
1792 if (!stream->is_feed) {
1793 /* However it might be a status report from WMP! Let us log the
1794 * data as it might come in handy one day. */
1795 const char *logline = 0;
1798 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1799 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1803 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1804 client_id = strtol(p + 18, 0, 10);
1805 p = strchr(p, '\n');
1813 char *eol = strchr(logline, '\n');
1818 if (eol[-1] == '\r')
1820 http_log("%.*s\n", (int) (eol - logline), logline);
1821 c->suppress_log = 1;
1826 http_log("\nGot request:\n%s\n", c->buffer);
1829 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1832 /* Now we have to find the client_id */
1833 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1834 if (wmpc->wmp_client_id == client_id)
1838 if (wmpc && modify_current_stream(wmpc, ratebuf))
1839 wmpc->switch_pending = 1;
1842 snprintf(msg, sizeof(msg), "POST command not handled");
1846 if (http_start_receive_data(c) < 0) {
1847 snprintf(msg, sizeof(msg), "could not open feed");
1851 c->state = HTTPSTATE_RECEIVE_DATA;
1856 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1857 http_log("\nGot request:\n%s\n", c->buffer);
1860 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1863 /* open input stream */
1864 if (open_input_stream(c, info) < 0) {
1865 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1869 /* prepare http header */
1871 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1872 mime_type = c->stream->fmt->mime_type;
1874 mime_type = "application/x-octet-stream";
1875 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1877 /* for asf, we need extra headers */
1878 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1879 /* Need to allocate a client id */
1881 c->wmp_client_id = av_lfg_get(&random_state);
1883 av_strlcatf(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);
1885 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1886 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1887 q = c->buffer + strlen(c->buffer);
1889 /* prepare output buffer */
1891 c->buffer_ptr = c->buffer;
1893 c->state = HTTPSTATE_SEND_HEADER;
1896 c->http_error = 404;
1899 snprintf(q, c->buffer_size,
1900 "HTTP/1.0 404 Not Found\r\n"
1901 "Content-type: text/html\r\n"
1904 "<head><title>404 Not Found</title></head>\n"
1908 /* prepare output buffer */
1909 c->buffer_ptr = c->buffer;
1911 c->state = HTTPSTATE_SEND_HEADER;
1915 c->http_error = 200; /* horrible : we use this value to avoid
1916 going to the send data state */
1917 c->state = HTTPSTATE_SEND_HEADER;
1921 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1923 static const char suffix[] = " kMGTP";
1926 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1928 avio_printf(pb, "%"PRId64"%c", count, *s);
1931 static void compute_status(HTTPContext *c)
1940 if (avio_open_dyn_buf(&pb) < 0) {
1941 /* XXX: return an error ? */
1942 c->buffer_ptr = c->buffer;
1943 c->buffer_end = c->buffer;
1947 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1948 avio_printf(pb, "Content-type: %s\r\n", "text/html");
1949 avio_printf(pb, "Pragma: no-cache\r\n");
1950 avio_printf(pb, "\r\n");
1952 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1953 if (c->stream->feed_filename[0])
1954 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1955 avio_printf(pb, "</head>\n<body>");
1956 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1958 avio_printf(pb, "<h2>Available Streams</h2>\n");
1959 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1960 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");
1961 stream = first_stream;
1962 while (stream != NULL) {
1963 char sfilename[1024];
1966 if (stream->feed != stream) {
1967 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1968 eosf = sfilename + strlen(sfilename);
1969 if (eosf - sfilename >= 4) {
1970 if (strcmp(eosf - 4, ".asf") == 0)
1971 strcpy(eosf - 4, ".asx");
1972 else if (strcmp(eosf - 3, ".rm") == 0)
1973 strcpy(eosf - 3, ".ram");
1974 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1975 /* generate a sample RTSP director if
1976 unicast. Generate an SDP redirector if
1978 eosf = strrchr(sfilename, '.');
1980 eosf = sfilename + strlen(sfilename);
1981 if (stream->is_multicast)
1982 strcpy(eosf, ".sdp");
1984 strcpy(eosf, ".rtsp");
1988 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1989 sfilename, stream->filename);
1990 avio_printf(pb, "<td align=right> %d <td align=right> ",
1991 stream->conns_served);
1992 fmt_bytecount(pb, stream->bytes_served);
1993 switch(stream->stream_type) {
1994 case STREAM_TYPE_LIVE: {
1995 int audio_bit_rate = 0;
1996 int video_bit_rate = 0;
1997 const char *audio_codec_name = "";
1998 const char *video_codec_name = "";
1999 const char *audio_codec_name_extra = "";
2000 const char *video_codec_name_extra = "";
2002 for(i=0;i<stream->nb_streams;i++) {
2003 AVStream *st = stream->streams[i];
2004 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2005 switch(st->codec->codec_type) {
2006 case AVMEDIA_TYPE_AUDIO:
2007 audio_bit_rate += st->codec->bit_rate;
2009 if (*audio_codec_name)
2010 audio_codec_name_extra = "...";
2011 audio_codec_name = codec->name;
2014 case AVMEDIA_TYPE_VIDEO:
2015 video_bit_rate += st->codec->bit_rate;
2017 if (*video_codec_name)
2018 video_codec_name_extra = "...";
2019 video_codec_name = codec->name;
2022 case AVMEDIA_TYPE_DATA:
2023 video_bit_rate += st->codec->bit_rate;
2029 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",
2032 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2033 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2035 avio_printf(pb, "<td>%s", stream->feed->filename);
2037 avio_printf(pb, "<td>%s", stream->feed_filename);
2038 avio_printf(pb, "\n");
2042 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2046 stream = stream->next;
2048 avio_printf(pb, "</table>\n");
2050 stream = first_stream;
2051 while (stream != NULL) {
2052 if (stream->feed == stream) {
2053 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2055 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2062 /* This is somewhat linux specific I guess */
2063 snprintf(ps_cmd, sizeof(ps_cmd),
2064 "ps -o \"%%cpu,cputime\" --no-headers %d",
2067 pid_stat = popen(ps_cmd, "r");
2072 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2074 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2082 avio_printf(pb, "<p>");
2084 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");
2086 for (i = 0; i < stream->nb_streams; i++) {
2087 AVStream *st = stream->streams[i];
2088 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2089 const char *type = "unknown";
2090 char parameters[64];
2094 switch(st->codec->codec_type) {
2095 case AVMEDIA_TYPE_AUDIO:
2097 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2099 case AVMEDIA_TYPE_VIDEO:
2101 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2102 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2107 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2108 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2110 avio_printf(pb, "</table>\n");
2113 stream = stream->next;
2116 /* connection status */
2117 avio_printf(pb, "<h2>Connection Status</h2>\n");
2119 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2120 nb_connections, nb_max_connections);
2122 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2123 current_bandwidth, max_bandwidth);
2125 avio_printf(pb, "<table>\n");
2126 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");
2127 c1 = first_http_ctx;
2129 while (c1 != NULL) {
2135 for (j = 0; j < c1->stream->nb_streams; j++) {
2136 if (!c1->stream->feed)
2137 bitrate += c1->stream->streams[j]->codec->bit_rate;
2138 else if (c1->feed_streams[j] >= 0)
2139 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2144 p = inet_ntoa(c1->from_addr.sin_addr);
2145 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2147 c1->stream ? c1->stream->filename : "",
2148 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2151 http_state[c1->state]);
2152 fmt_bytecount(pb, bitrate);
2153 avio_printf(pb, "<td align=right>");
2154 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2155 avio_printf(pb, "<td align=right>");
2156 fmt_bytecount(pb, c1->data_count);
2157 avio_printf(pb, "\n");
2160 avio_printf(pb, "</table>\n");
2165 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2166 avio_printf(pb, "</body>\n</html>\n");
2168 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2169 c->buffer_ptr = c->pb_buffer;
2170 c->buffer_end = c->pb_buffer + len;
2173 static int open_input_stream(HTTPContext *c, const char *info)
2176 char input_filename[1024];
2177 AVFormatContext *s = NULL;
2178 int buf_size, i, ret;
2181 /* find file name */
2182 if (c->stream->feed) {
2183 strcpy(input_filename, c->stream->feed->feed_filename);
2184 buf_size = FFM_PACKET_SIZE;
2185 /* compute position (absolute time) */
2186 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2187 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2188 http_log("Invalid date specification '%s' for stream\n", buf);
2191 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2192 int prebuffer = strtol(buf, 0, 10);
2193 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2195 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2197 strcpy(input_filename, c->stream->feed_filename);
2199 /* compute position (relative time) */
2200 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2201 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2202 http_log("Invalid date specification '%s' for stream\n", buf);
2208 if (!input_filename[0]) {
2209 http_log("No filename was specified for stream\n");
2210 return AVERROR(EINVAL);
2214 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2215 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2219 /* set buffer size */
2220 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2222 s->flags |= AVFMT_FLAG_GENPTS;
2224 if (strcmp(s->iformat->name, "ffm") &&
2225 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2226 http_log("Could not find stream info for input '%s'\n", input_filename);
2227 avformat_close_input(&s);
2231 /* choose stream as clock source (we favorize video stream if
2232 present) for packet sending */
2233 c->pts_stream_index = 0;
2234 for(i=0;i<c->stream->nb_streams;i++) {
2235 if (c->pts_stream_index == 0 &&
2236 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2237 c->pts_stream_index = i;
2241 if (c->fmt_in->iformat->read_seek)
2242 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2243 /* set the start time (needed for maxtime and RTP packet timing) */
2244 c->start_time = cur_time;
2245 c->first_pts = AV_NOPTS_VALUE;
2249 /* return the server clock (in us) */
2250 static int64_t get_server_clock(HTTPContext *c)
2252 /* compute current pts value from system time */
2253 return (cur_time - c->start_time) * 1000;
2256 /* return the estimated time at which the current packet must be sent
2258 static int64_t get_packet_send_clock(HTTPContext *c)
2260 int bytes_left, bytes_sent, frame_bytes;
2262 frame_bytes = c->cur_frame_bytes;
2263 if (frame_bytes <= 0)
2266 bytes_left = c->buffer_end - c->buffer_ptr;
2267 bytes_sent = frame_bytes - bytes_left;
2268 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2273 static int http_prepare_data(HTTPContext *c)
2276 AVFormatContext *ctx;
2278 av_freep(&c->pb_buffer);
2280 case HTTPSTATE_SEND_DATA_HEADER:
2281 memset(&c->fmt_ctx, 0, sizeof(c->fmt_ctx));
2282 av_dict_set(&c->fmt_ctx.metadata, "author" , c->stream->author , 0);
2283 av_dict_set(&c->fmt_ctx.metadata, "comment" , c->stream->comment , 0);
2284 av_dict_set(&c->fmt_ctx.metadata, "copyright", c->stream->copyright, 0);
2285 av_dict_set(&c->fmt_ctx.metadata, "title" , c->stream->title , 0);
2287 c->fmt_ctx.streams = av_mallocz(sizeof(AVStream *) * c->stream->nb_streams);
2289 for(i=0;i<c->stream->nb_streams;i++) {
2291 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2292 /* if file or feed, then just take streams from FFStream struct */
2293 if (!c->stream->feed ||
2294 c->stream->feed == c->stream)
2295 src = c->stream->streams[i];
2297 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2299 *(c->fmt_ctx.streams[i]) = *src;
2300 c->fmt_ctx.streams[i]->priv_data = 0;
2301 c->fmt_ctx.streams[i]->codec->frame_number = 0; /* XXX: should be done in
2302 AVStream, not in codec */
2304 /* set output format parameters */
2305 c->fmt_ctx.oformat = c->stream->fmt;
2306 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2308 c->got_key_frame = 0;
2310 /* prepare header and save header data in a stream */
2311 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2312 /* XXX: potential leak */
2315 c->fmt_ctx.pb->seekable = 0;
2318 * HACK to avoid mpeg ps muxer to spit many underflow errors
2319 * Default value from FFmpeg
2320 * Try to set it use configuration option
2322 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2324 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2325 http_log("Error writing output header for stream '%s': %s\n",
2326 c->stream->filename, av_err2str(ret));
2329 av_dict_free(&c->fmt_ctx.metadata);
2331 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2332 c->buffer_ptr = c->pb_buffer;
2333 c->buffer_end = c->pb_buffer + len;
2335 c->state = HTTPSTATE_SEND_DATA;
2336 c->last_packet_sent = 0;
2338 case HTTPSTATE_SEND_DATA:
2339 /* find a new packet */
2340 /* read a packet from the input stream */
2341 if (c->stream->feed)
2342 ffm_set_write_index(c->fmt_in,
2343 c->stream->feed->feed_write_index,
2344 c->stream->feed->feed_size);
2346 if (c->stream->max_time &&
2347 c->stream->max_time + c->start_time - cur_time < 0)
2348 /* We have timed out */
2349 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2353 ret = av_read_frame(c->fmt_in, &pkt);
2355 if (c->stream->feed) {
2356 /* if coming from feed, it means we reached the end of the
2357 ffm file, so must wait for more data */
2358 c->state = HTTPSTATE_WAIT_FEED;
2359 return 1; /* state changed */
2360 } else if (ret == AVERROR(EAGAIN)) {
2361 /* input not ready, come back later */
2364 if (c->stream->loop) {
2365 avformat_close_input(&c->fmt_in);
2366 if (open_input_stream(c, "") < 0)
2371 /* must send trailer now because eof or error */
2372 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2376 int source_index = pkt.stream_index;
2377 /* update first pts if needed */
2378 if (c->first_pts == AV_NOPTS_VALUE) {
2379 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2380 c->start_time = cur_time;
2382 /* send it to the appropriate stream */
2383 if (c->stream->feed) {
2384 /* if coming from a feed, select the right stream */
2385 if (c->switch_pending) {
2386 c->switch_pending = 0;
2387 for(i=0;i<c->stream->nb_streams;i++) {
2388 if (c->switch_feed_streams[i] == pkt.stream_index)
2389 if (pkt.flags & AV_PKT_FLAG_KEY)
2390 c->switch_feed_streams[i] = -1;
2391 if (c->switch_feed_streams[i] >= 0)
2392 c->switch_pending = 1;
2395 for(i=0;i<c->stream->nb_streams;i++) {
2396 if (c->stream->feed_streams[i] == pkt.stream_index) {
2397 AVStream *st = c->fmt_in->streams[source_index];
2398 pkt.stream_index = i;
2399 if (pkt.flags & AV_PKT_FLAG_KEY &&
2400 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2401 c->stream->nb_streams == 1))
2402 c->got_key_frame = 1;
2403 if (!c->stream->send_on_key || c->got_key_frame)
2408 AVCodecContext *codec;
2409 AVStream *ist, *ost;
2411 ist = c->fmt_in->streams[source_index];
2412 /* specific handling for RTP: we use several
2413 output stream (one for each RTP
2414 connection). XXX: need more abstract handling */
2415 if (c->is_packetized) {
2416 /* compute send time and duration */
2417 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2418 c->cur_pts -= c->first_pts;
2419 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2420 /* find RTP context */
2421 c->packet_stream_index = pkt.stream_index;
2422 ctx = c->rtp_ctx[c->packet_stream_index];
2424 av_free_packet(&pkt);
2427 codec = ctx->streams[0]->codec;
2428 /* only one stream per RTP connection */
2429 pkt.stream_index = 0;
2433 codec = ctx->streams[pkt.stream_index]->codec;
2436 if (c->is_packetized) {
2437 int max_packet_size;
2438 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2439 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2441 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2442 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2444 ret = avio_open_dyn_buf(&ctx->pb);
2447 /* XXX: potential leak */
2450 ost = ctx->streams[pkt.stream_index];
2452 ctx->pb->seekable = 0;
2453 if (pkt.dts != AV_NOPTS_VALUE)
2454 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2455 if (pkt.pts != AV_NOPTS_VALUE)
2456 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2457 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2458 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2459 http_log("Error writing frame to output for stream '%s': %s\n",
2460 c->stream->filename, av_err2str(ret));
2461 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2464 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2465 c->cur_frame_bytes = len;
2466 c->buffer_ptr = c->pb_buffer;
2467 c->buffer_end = c->pb_buffer + len;
2469 codec->frame_number++;
2471 av_free_packet(&pkt);
2475 av_free_packet(&pkt);
2480 case HTTPSTATE_SEND_DATA_TRAILER:
2481 /* last packet test ? */
2482 if (c->last_packet_sent || c->is_packetized)
2485 /* prepare header */
2486 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2487 /* XXX: potential leak */
2490 c->fmt_ctx.pb->seekable = 0;
2491 av_write_trailer(ctx);
2492 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2493 c->buffer_ptr = c->pb_buffer;
2494 c->buffer_end = c->pb_buffer + len;
2496 c->last_packet_sent = 1;
2502 /* should convert the format at the same time */
2503 /* send data starting at c->buffer_ptr to the output connection
2504 (either UDP or TCP connection) */
2505 static int http_send_data(HTTPContext *c)
2510 if (c->buffer_ptr >= c->buffer_end) {
2511 ret = http_prepare_data(c);
2515 /* state change requested */
2518 if (c->is_packetized) {
2519 /* RTP data output */
2520 len = c->buffer_end - c->buffer_ptr;
2522 /* fail safe - should never happen */
2524 c->buffer_ptr = c->buffer_end;
2527 len = (c->buffer_ptr[0] << 24) |
2528 (c->buffer_ptr[1] << 16) |
2529 (c->buffer_ptr[2] << 8) |
2531 if (len > (c->buffer_end - c->buffer_ptr))
2533 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2534 /* nothing to send yet: we can wait */
2538 c->data_count += len;
2539 update_datarate(&c->datarate, c->data_count);
2541 c->stream->bytes_served += len;
2543 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2544 /* RTP packets are sent inside the RTSP TCP connection */
2546 int interleaved_index, size;
2548 HTTPContext *rtsp_c;
2551 /* if no RTSP connection left, error */
2554 /* if already sending something, then wait. */
2555 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2557 if (avio_open_dyn_buf(&pb) < 0)
2559 interleaved_index = c->packet_stream_index * 2;
2560 /* RTCP packets are sent at odd indexes */
2561 if (c->buffer_ptr[1] == 200)
2562 interleaved_index++;
2563 /* write RTSP TCP header */
2565 header[1] = interleaved_index;
2566 header[2] = len >> 8;
2568 avio_write(pb, header, 4);
2569 /* write RTP packet data */
2571 avio_write(pb, c->buffer_ptr, len);
2572 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2573 /* prepare asynchronous TCP sending */
2574 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2575 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2576 c->buffer_ptr += len;
2578 /* send everything we can NOW */
2579 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2580 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2582 rtsp_c->packet_buffer_ptr += len;
2583 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2584 /* if we could not send all the data, we will
2585 send it later, so a new state is needed to
2586 "lock" the RTSP TCP connection */
2587 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2590 /* all data has been sent */
2591 av_freep(&c->packet_buffer);
2593 /* send RTP packet directly in UDP */
2595 ffurl_write(c->rtp_handles[c->packet_stream_index],
2596 c->buffer_ptr, len);
2597 c->buffer_ptr += len;
2598 /* here we continue as we can send several packets per 10 ms slot */
2601 /* TCP data output */
2602 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2604 if (ff_neterrno() != AVERROR(EAGAIN) &&
2605 ff_neterrno() != AVERROR(EINTR))
2606 /* error : close connection */
2611 c->buffer_ptr += len;
2613 c->data_count += len;
2614 update_datarate(&c->datarate, c->data_count);
2616 c->stream->bytes_served += len;
2624 static int http_start_receive_data(HTTPContext *c)
2629 if (c->stream->feed_opened) {
2630 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2631 return AVERROR(EINVAL);
2634 /* Don't permit writing to this one */
2635 if (c->stream->readonly) {
2636 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2637 return AVERROR(EINVAL);
2641 fd = open(c->stream->feed_filename, O_RDWR);
2643 ret = AVERROR(errno);
2644 http_log("Could not open feed file '%s':%s \n",
2645 c->stream->feed_filename, strerror(errno));
2650 if (c->stream->truncate) {
2651 /* truncate feed file */
2652 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2653 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2654 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2655 ret = AVERROR(errno);
2656 http_log("Error truncating feed file '%s': %s\n",
2657 c->stream->feed_filename, strerror(errno));
2661 ret = ffm_read_write_index(fd);
2663 http_log("Error reading write index from feed file '%s': %s\n",
2664 c->stream->feed_filename, strerror(errno));
2667 c->stream->feed_write_index = ret;
2671 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2672 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2673 lseek(fd, 0, SEEK_SET);
2675 /* init buffer input */
2676 c->buffer_ptr = c->buffer;
2677 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2678 c->stream->feed_opened = 1;
2679 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2683 static int http_receive_data(HTTPContext *c)
2686 int len, loop_run = 0;
2688 while (c->chunked_encoding && !c->chunk_size &&
2689 c->buffer_end > c->buffer_ptr) {
2690 /* read chunk header, if present */
2691 len = recv(c->fd, c->buffer_ptr, 1, 0);
2694 if (ff_neterrno() != AVERROR(EAGAIN) &&
2695 ff_neterrno() != AVERROR(EINTR))
2696 /* error : close connection */
2699 } else if (len == 0) {
2700 /* end of connection : close it */
2702 } else if (c->buffer_ptr - c->buffer >= 2 &&
2703 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2704 c->chunk_size = strtol(c->buffer, 0, 16);
2705 if (c->chunk_size == 0) // end of stream
2707 c->buffer_ptr = c->buffer;
2709 } else if (++loop_run > 10) {
2710 /* no chunk header, abort */
2717 if (c->buffer_end > c->buffer_ptr) {
2718 len = recv(c->fd, c->buffer_ptr,
2719 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2721 if (ff_neterrno() != AVERROR(EAGAIN) &&
2722 ff_neterrno() != AVERROR(EINTR))
2723 /* error : close connection */
2725 } else if (len == 0)
2726 /* end of connection : close it */
2729 c->chunk_size -= len;
2730 c->buffer_ptr += len;
2731 c->data_count += len;
2732 update_datarate(&c->datarate, c->data_count);
2736 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2737 if (c->buffer[0] != 'f' ||
2738 c->buffer[1] != 'm') {
2739 http_log("Feed stream has become desynchronized -- disconnecting\n");
2744 if (c->buffer_ptr >= c->buffer_end) {
2745 FFStream *feed = c->stream;
2746 /* a packet has been received : write it in the store, except
2748 if (c->data_count > FFM_PACKET_SIZE) {
2749 /* XXX: use llseek or url_seek */
2750 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2751 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2752 http_log("Error writing to feed file: %s\n", strerror(errno));
2756 feed->feed_write_index += FFM_PACKET_SIZE;
2757 /* update file size */
2758 if (feed->feed_write_index > c->stream->feed_size)
2759 feed->feed_size = feed->feed_write_index;
2761 /* handle wrap around if max file size reached */
2762 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2763 feed->feed_write_index = FFM_PACKET_SIZE;
2766 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2767 http_log("Error writing index to feed file: %s\n", strerror(errno));
2771 /* wake up any waiting connections */
2772 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2773 if (c1->state == HTTPSTATE_WAIT_FEED &&
2774 c1->stream->feed == c->stream->feed)
2775 c1->state = HTTPSTATE_SEND_DATA;
2778 /* We have a header in our hands that contains useful data */
2779 AVFormatContext *s = avformat_alloc_context();
2781 AVInputFormat *fmt_in;
2787 /* use feed output format name to find corresponding input format */
2788 fmt_in = av_find_input_format(feed->fmt->name);
2792 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2793 0, NULL, NULL, NULL, NULL);
2797 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2802 /* Now we have the actual streams */
2803 if (s->nb_streams != feed->nb_streams) {
2804 avformat_close_input(&s);
2806 http_log("Feed '%s' stream number does not match registered feed\n",
2807 c->stream->feed_filename);
2811 for (i = 0; i < s->nb_streams; i++) {
2812 AVStream *fst = feed->streams[i];
2813 AVStream *st = s->streams[i];
2814 avcodec_copy_context(fst->codec, st->codec);
2817 avformat_close_input(&s);
2820 c->buffer_ptr = c->buffer;
2825 c->stream->feed_opened = 0;
2827 /* wake up any waiting connections to stop waiting for feed */
2828 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2829 if (c1->state == HTTPSTATE_WAIT_FEED &&
2830 c1->stream->feed == c->stream->feed)
2831 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2836 /********************************************************************/
2839 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2846 switch(error_number) {
2847 case RTSP_STATUS_OK:
2850 case RTSP_STATUS_METHOD:
2851 str = "Method Not Allowed";
2853 case RTSP_STATUS_BANDWIDTH:
2854 str = "Not Enough Bandwidth";
2856 case RTSP_STATUS_SESSION:
2857 str = "Session Not Found";
2859 case RTSP_STATUS_STATE:
2860 str = "Method Not Valid in This State";
2862 case RTSP_STATUS_AGGREGATE:
2863 str = "Aggregate operation not allowed";
2865 case RTSP_STATUS_ONLY_AGGREGATE:
2866 str = "Only aggregate operation allowed";
2868 case RTSP_STATUS_TRANSPORT:
2869 str = "Unsupported transport";
2871 case RTSP_STATUS_INTERNAL:
2872 str = "Internal Server Error";
2874 case RTSP_STATUS_SERVICE:
2875 str = "Service Unavailable";
2877 case RTSP_STATUS_VERSION:
2878 str = "RTSP Version not supported";
2881 str = "Unknown Error";
2885 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2886 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2888 /* output GMT time */
2891 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2892 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2895 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2897 rtsp_reply_header(c, error_number);
2898 avio_printf(c->pb, "\r\n");
2901 static int rtsp_parse_request(HTTPContext *c)
2903 const char *p, *p1, *p2;
2909 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2911 c->buffer_ptr[0] = '\0';
2914 get_word(cmd, sizeof(cmd), &p);
2915 get_word(url, sizeof(url), &p);
2916 get_word(protocol, sizeof(protocol), &p);
2918 av_strlcpy(c->method, cmd, sizeof(c->method));
2919 av_strlcpy(c->url, url, sizeof(c->url));
2920 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2922 if (avio_open_dyn_buf(&c->pb) < 0) {
2923 /* XXX: cannot do more */
2924 c->pb = NULL; /* safety */
2928 /* check version name */
2929 if (strcmp(protocol, "RTSP/1.0") != 0) {
2930 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2934 /* parse each header line */
2935 /* skip to next line */
2936 while (*p != '\n' && *p != '\0')
2940 while (*p != '\0') {
2941 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2945 if (p2 > p && p2[-1] == '\r')
2947 /* skip empty line */
2951 if (len > sizeof(line) - 1)
2952 len = sizeof(line) - 1;
2953 memcpy(line, p, len);
2955 ff_rtsp_parse_line(header, line, NULL, NULL);
2959 /* handle sequence number */
2960 c->seq = header->seq;
2962 if (!strcmp(cmd, "DESCRIBE"))
2963 rtsp_cmd_describe(c, url);
2964 else if (!strcmp(cmd, "OPTIONS"))
2965 rtsp_cmd_options(c, url);
2966 else if (!strcmp(cmd, "SETUP"))
2967 rtsp_cmd_setup(c, url, header);
2968 else if (!strcmp(cmd, "PLAY"))
2969 rtsp_cmd_play(c, url, header);
2970 else if (!strcmp(cmd, "PAUSE"))
2971 rtsp_cmd_pause(c, url, header);
2972 else if (!strcmp(cmd, "TEARDOWN"))
2973 rtsp_cmd_teardown(c, url, header);
2975 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2978 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2979 c->pb = NULL; /* safety */
2981 /* XXX: cannot do more */
2984 c->buffer_ptr = c->pb_buffer;
2985 c->buffer_end = c->pb_buffer + len;
2986 c->state = RTSPSTATE_SEND_REPLY;
2990 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2991 struct in_addr my_ip)
2993 AVFormatContext *avc;
2994 AVStream *avs = NULL;
2995 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2998 avc = avformat_alloc_context();
2999 if (avc == NULL || !rtp_format) {
3002 avc->oformat = rtp_format;
3003 av_dict_set(&avc->metadata, "title",
3004 stream->title[0] ? stream->title : "No Title", 0);
3005 avc->nb_streams = stream->nb_streams;
3006 if (stream->is_multicast) {
3007 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
3008 inet_ntoa(stream->multicast_ip),
3009 stream->multicast_port, stream->multicast_ttl);
3011 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
3014 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
3015 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
3017 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
3018 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
3021 for(i = 0; i < stream->nb_streams; i++) {
3022 avc->streams[i] = &avs[i];
3023 avc->streams[i]->codec = stream->streams[i]->codec;
3025 *pbuffer = av_mallocz(2048);
3026 av_sdp_create(&avc, 1, *pbuffer, 2048);
3029 av_free(avc->streams);
3030 av_dict_free(&avc->metadata);
3034 return strlen(*pbuffer);
3037 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3039 // rtsp_reply_header(c, RTSP_STATUS_OK);
3040 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3041 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3042 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3043 avio_printf(c->pb, "\r\n");
3046 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3054 struct sockaddr_in my_addr;
3056 /* find which url is asked */
3057 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3062 for(stream = first_stream; stream != NULL; stream = stream->next) {
3063 if (!stream->is_feed &&
3064 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3065 !strcmp(path, stream->filename)) {
3069 /* no stream found */
3070 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3074 /* prepare the media description in sdp format */
3076 /* get the host IP */
3077 len = sizeof(my_addr);
3078 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3079 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3080 if (content_length < 0) {
3081 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3084 rtsp_reply_header(c, RTSP_STATUS_OK);
3085 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3086 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3087 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3088 avio_printf(c->pb, "\r\n");
3089 avio_write(c->pb, content, content_length);
3093 static HTTPContext *find_rtp_session(const char *session_id)
3097 if (session_id[0] == '\0')
3100 for(c = first_http_ctx; c != NULL; c = c->next) {
3101 if (!strcmp(c->session_id, session_id))
3107 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3109 RTSPTransportField *th;
3112 for(i=0;i<h->nb_transports;i++) {
3113 th = &h->transports[i];
3114 if (th->lower_transport == lower_transport)
3120 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3121 RTSPMessageHeader *h)
3124 int stream_index, rtp_port, rtcp_port;
3129 RTSPTransportField *th;
3130 struct sockaddr_in dest_addr;
3131 RTSPActionServerSetup setup;
3133 /* find which url is asked */
3134 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3139 /* now check each stream */
3140 for(stream = first_stream; stream != NULL; stream = stream->next) {
3141 if (!stream->is_feed &&
3142 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3143 /* accept aggregate filenames only if single stream */
3144 if (!strcmp(path, stream->filename)) {
3145 if (stream->nb_streams != 1) {
3146 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3153 for(stream_index = 0; stream_index < stream->nb_streams;
3155 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3156 stream->filename, stream_index);
3157 if (!strcmp(path, buf))
3162 /* no stream found */
3163 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3167 /* generate session id if needed */
3168 if (h->session_id[0] == '\0') {
3169 unsigned random0 = av_lfg_get(&random_state);
3170 unsigned random1 = av_lfg_get(&random_state);
3171 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3175 /* find rtp session, and create it if none found */
3176 rtp_c = find_rtp_session(h->session_id);
3178 /* always prefer UDP */
3179 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3181 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3183 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3188 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3189 th->lower_transport);
3191 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3195 /* open input stream */
3196 if (open_input_stream(rtp_c, "") < 0) {
3197 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3202 /* test if stream is OK (test needed because several SETUP needs
3203 to be done for a given file) */
3204 if (rtp_c->stream != stream) {
3205 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3209 /* test if stream is already set up */
3210 if (rtp_c->rtp_ctx[stream_index]) {
3211 rtsp_reply_error(c, RTSP_STATUS_STATE);
3215 /* check transport */
3216 th = find_transport(h, rtp_c->rtp_protocol);
3217 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3218 th->client_port_min <= 0)) {
3219 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3223 /* setup default options */
3224 setup.transport_option[0] = '\0';
3225 dest_addr = rtp_c->from_addr;
3226 dest_addr.sin_port = htons(th->client_port_min);
3229 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3230 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3234 /* now everything is OK, so we can send the connection parameters */
3235 rtsp_reply_header(c, RTSP_STATUS_OK);
3237 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3239 switch(rtp_c->rtp_protocol) {
3240 case RTSP_LOWER_TRANSPORT_UDP:
3241 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3242 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3243 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3244 "client_port=%d-%d;server_port=%d-%d",
3245 th->client_port_min, th->client_port_max,
3246 rtp_port, rtcp_port);
3248 case RTSP_LOWER_TRANSPORT_TCP:
3249 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3250 stream_index * 2, stream_index * 2 + 1);
3255 if (setup.transport_option[0] != '\0')
3256 avio_printf(c->pb, ";%s", setup.transport_option);
3257 avio_printf(c->pb, "\r\n");
3260 avio_printf(c->pb, "\r\n");
3264 /* find an rtp connection by using the session ID. Check consistency
3266 static HTTPContext *find_rtp_session_with_url(const char *url,
3267 const char *session_id)
3275 rtp_c = find_rtp_session(session_id);
3279 /* find which url is asked */
3280 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3284 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3285 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3286 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3287 rtp_c->stream->filename, s);
3288 if(!strncmp(path, buf, sizeof(buf))) {
3289 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3294 if (len > 0 && path[len - 1] == '/' &&
3295 !strncmp(path, rtp_c->stream->filename, len - 1))
3300 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3304 rtp_c = find_rtp_session_with_url(url, h->session_id);
3306 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3310 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3311 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3312 rtp_c->state != HTTPSTATE_READY) {
3313 rtsp_reply_error(c, RTSP_STATUS_STATE);
3317 rtp_c->state = HTTPSTATE_SEND_DATA;
3319 /* now everything is OK, so we can send the connection parameters */
3320 rtsp_reply_header(c, RTSP_STATUS_OK);
3322 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3323 avio_printf(c->pb, "\r\n");
3326 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3330 rtp_c = find_rtp_session_with_url(url, h->session_id);
3332 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3336 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3337 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3338 rtsp_reply_error(c, RTSP_STATUS_STATE);
3342 rtp_c->state = HTTPSTATE_READY;
3343 rtp_c->first_pts = AV_NOPTS_VALUE;
3344 /* now everything is OK, so we can send the connection parameters */
3345 rtsp_reply_header(c, RTSP_STATUS_OK);
3347 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3348 avio_printf(c->pb, "\r\n");
3351 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3355 rtp_c = find_rtp_session_with_url(url, h->session_id);
3357 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3361 /* now everything is OK, so we can send the connection parameters */
3362 rtsp_reply_header(c, RTSP_STATUS_OK);
3364 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3365 avio_printf(c->pb, "\r\n");
3367 /* abort the session */
3368 close_connection(rtp_c);
3372 /********************************************************************/
3375 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3376 FFStream *stream, const char *session_id,
3377 enum RTSPLowerTransport rtp_protocol)
3379 HTTPContext *c = NULL;
3380 const char *proto_str;
3382 /* XXX: should output a warning page when coming
3383 close to the connection limit */
3384 if (nb_connections >= nb_max_connections)
3387 /* add a new connection */
3388 c = av_mallocz(sizeof(HTTPContext));
3393 c->poll_entry = NULL;
3394 c->from_addr = *from_addr;
3395 c->buffer_size = IOBUFFER_INIT_SIZE;
3396 c->buffer = av_malloc(c->buffer_size);
3401 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3402 c->state = HTTPSTATE_READY;
3403 c->is_packetized = 1;
3404 c->rtp_protocol = rtp_protocol;
3406 /* protocol is shown in statistics */
3407 switch(c->rtp_protocol) {
3408 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3409 proto_str = "MCAST";
3411 case RTSP_LOWER_TRANSPORT_UDP:
3414 case RTSP_LOWER_TRANSPORT_TCP:
3421 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3422 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3424 current_bandwidth += stream->bandwidth;
3426 c->next = first_http_ctx;
3438 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3439 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3441 static int rtp_new_av_stream(HTTPContext *c,
3442 int stream_index, struct sockaddr_in *dest_addr,
3443 HTTPContext *rtsp_c)
3445 AVFormatContext *ctx;
3448 URLContext *h = NULL;
3450 int max_packet_size;
3452 /* now we can open the relevant output stream */
3453 ctx = avformat_alloc_context();
3456 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3458 st = av_mallocz(sizeof(AVStream));
3461 ctx->nb_streams = 1;
3462 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3465 ctx->streams[0] = st;
3467 if (!c->stream->feed ||
3468 c->stream->feed == c->stream)
3469 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3472 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3474 st->priv_data = NULL;
3476 /* build destination RTP address */
3477 ipaddr = inet_ntoa(dest_addr->sin_addr);
3479 switch(c->rtp_protocol) {
3480 case RTSP_LOWER_TRANSPORT_UDP:
3481 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3484 /* XXX: also pass as parameter to function ? */
3485 if (c->stream->is_multicast) {
3487 ttl = c->stream->multicast_ttl;
3490 snprintf(ctx->filename, sizeof(ctx->filename),
3491 "rtp://%s:%d?multicast=1&ttl=%d",
3492 ipaddr, ntohs(dest_addr->sin_port), ttl);
3494 snprintf(ctx->filename, sizeof(ctx->filename),
3495 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3498 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3500 c->rtp_handles[stream_index] = h;
3501 max_packet_size = h->max_packet_size;
3503 case RTSP_LOWER_TRANSPORT_TCP:
3506 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3512 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3513 ipaddr, ntohs(dest_addr->sin_port),
3514 c->stream->filename, stream_index, c->protocol);
3516 /* normally, no packets should be output here, but the packet size may be checked */
3517 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3518 /* XXX: close stream */
3521 if (avformat_write_header(ctx, NULL) < 0) {
3528 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3531 c->rtp_ctx[stream_index] = ctx;
3535 /********************************************************************/
3536 /* ffserver initialization */
3538 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3542 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3545 fst = av_mallocz(sizeof(AVStream));
3549 fst->codec = avcodec_alloc_context3(NULL);
3550 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3551 if (codec->extradata_size) {
3552 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3553 memcpy(fst->codec->extradata, codec->extradata,
3554 codec->extradata_size);
3557 /* live streams must use the actual feed's codec since it may be
3558 * updated later to carry extradata needed by the streams.
3562 fst->priv_data = av_mallocz(sizeof(FeedData));
3563 fst->index = stream->nb_streams;
3564 avpriv_set_pts_info(fst, 33, 1, 90000);
3565 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3566 stream->streams[stream->nb_streams++] = fst;
3570 /* return the stream number in the feed */
3571 static int add_av_stream(FFStream *feed, AVStream *st)
3574 AVCodecContext *av, *av1;
3578 for(i=0;i<feed->nb_streams;i++) {
3579 st = feed->streams[i];
3581 if (av1->codec_id == av->codec_id &&
3582 av1->codec_type == av->codec_type &&
3583 av1->bit_rate == av->bit_rate) {
3585 switch(av->codec_type) {
3586 case AVMEDIA_TYPE_AUDIO:
3587 if (av1->channels == av->channels &&
3588 av1->sample_rate == av->sample_rate)
3591 case AVMEDIA_TYPE_VIDEO:
3592 if (av1->width == av->width &&
3593 av1->height == av->height &&
3594 av1->time_base.den == av->time_base.den &&
3595 av1->time_base.num == av->time_base.num &&
3596 av1->gop_size == av->gop_size)
3605 fst = add_av_stream1(feed, av, 0);
3608 return feed->nb_streams - 1;
3611 static void remove_stream(FFStream *stream)
3615 while (*ps != NULL) {
3623 /* specific mpeg4 handling : we extract the raw parameters */
3624 static void extract_mpeg4_header(AVFormatContext *infile)
3626 int mpeg4_count, i, size;
3631 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3634 for(i=0;i<infile->nb_streams;i++) {
3635 st = infile->streams[i];
3636 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3637 st->codec->extradata_size == 0) {
3644 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3645 while (mpeg4_count > 0) {
3646 if (av_read_frame(infile, &pkt) < 0)
3648 st = infile->streams[pkt.stream_index];
3649 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3650 st->codec->extradata_size == 0) {
3651 av_freep(&st->codec->extradata);
3652 /* fill extradata with the header */
3653 /* XXX: we make hard suppositions here ! */
3655 while (p < pkt.data + pkt.size - 4) {
3656 /* stop when vop header is found */
3657 if (p[0] == 0x00 && p[1] == 0x00 &&
3658 p[2] == 0x01 && p[3] == 0xb6) {
3659 size = p - pkt.data;
3660 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3661 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3662 st->codec->extradata_size = size;
3663 memcpy(st->codec->extradata, pkt.data, size);
3670 av_free_packet(&pkt);
3674 /* compute the needed AVStream for each file */
3675 static void build_file_streams(void)
3677 FFStream *stream, *stream_next;
3680 /* gather all streams */
3681 for(stream = first_stream; stream != NULL; stream = stream_next) {
3682 AVFormatContext *infile = NULL;
3683 stream_next = stream->next;
3684 if (stream->stream_type == STREAM_TYPE_LIVE &&
3686 /* the stream comes from a file */
3687 /* try to open the file */
3689 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3690 /* specific case : if transport stream output to RTP,
3691 we use a raw transport stream reader */
3692 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3695 if (!stream->feed_filename[0]) {
3696 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3700 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3701 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3702 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3703 /* remove stream (no need to spend more time on it) */
3705 remove_stream(stream);
3707 /* find all the AVStreams inside and reference them in
3709 if (avformat_find_stream_info(infile, NULL) < 0) {
3710 http_log("Could not find codec parameters from '%s'\n",
3711 stream->feed_filename);
3712 avformat_close_input(&infile);
3715 extract_mpeg4_header(infile);
3717 for(i=0;i<infile->nb_streams;i++)
3718 add_av_stream1(stream, infile->streams[i]->codec, 1);
3720 avformat_close_input(&infile);
3726 /* compute the needed AVStream for each feed */
3727 static void build_feed_streams(void)
3729 FFStream *stream, *feed;
3732 /* gather all streams */
3733 for(stream = first_stream; stream != NULL; stream = stream->next) {
3734 feed = stream->feed;
3736 if (stream->is_feed) {
3737 for(i=0;i<stream->nb_streams;i++)
3738 stream->feed_streams[i] = i;
3740 /* we handle a stream coming from a feed */
3741 for(i=0;i<stream->nb_streams;i++)
3742 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3747 /* create feed files if needed */
3748 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3751 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3752 /* See if it matches */
3753 AVFormatContext *s = NULL;
3756 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3757 /* set buffer size */
3758 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3759 /* Now see if it matches */
3760 if (s->nb_streams == feed->nb_streams) {
3762 for(i=0;i<s->nb_streams;i++) {
3764 sf = feed->streams[i];
3767 if (sf->index != ss->index ||
3769 http_log("Index & Id do not match for stream %d (%s)\n",
3770 i, feed->feed_filename);
3773 AVCodecContext *ccf, *ccs;
3777 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3779 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3780 http_log("Codecs do not match for stream %d\n", i);
3782 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3783 http_log("Codec bitrates do not match for stream %d\n", i);
3785 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3786 if (CHECK_CODEC(time_base.den) ||
3787 CHECK_CODEC(time_base.num) ||
3788 CHECK_CODEC(width) ||
3789 CHECK_CODEC(height)) {
3790 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3793 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3794 if (CHECK_CODEC(sample_rate) ||
3795 CHECK_CODEC(channels) ||
3796 CHECK_CODEC(frame_size)) {
3797 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3801 http_log("Unknown codec type\n");
3809 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3810 feed->feed_filename, s->nb_streams, feed->nb_streams);
3812 avformat_close_input(&s);
3814 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3815 feed->feed_filename);
3818 if (feed->readonly) {
3819 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3820 feed->feed_filename);
3823 unlink(feed->feed_filename);
3826 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3827 AVFormatContext s1 = {0}, *s = &s1;
3829 if (feed->readonly) {
3830 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3831 feed->feed_filename);
3835 /* only write the header of the ffm file */
3836 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3837 http_log("Could not open output feed file '%s'\n",
3838 feed->feed_filename);
3841 s->oformat = feed->fmt;
3842 s->nb_streams = feed->nb_streams;
3843 s->streams = feed->streams;
3844 if (avformat_write_header(s, NULL) < 0) {
3845 http_log("Container doesn't support the required parameters\n");
3848 /* XXX: need better api */
3849 av_freep(&s->priv_data);
3852 /* get feed size and write index */
3853 fd = open(feed->feed_filename, O_RDONLY);
3855 http_log("Could not open output feed file '%s'\n",
3856 feed->feed_filename);
3860 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3861 feed->feed_size = lseek(fd, 0, SEEK_END);
3862 /* ensure that we do not wrap before the end of file */
3863 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3864 feed->feed_max_size = feed->feed_size;
3870 /* compute the bandwidth used by each stream */
3871 static void compute_bandwidth(void)
3877 for(stream = first_stream; stream != NULL; stream = stream->next) {
3879 for(i=0;i<stream->nb_streams;i++) {
3880 AVStream *st = stream->streams[i];
3881 switch(st->codec->codec_type) {
3882 case AVMEDIA_TYPE_AUDIO:
3883 case AVMEDIA_TYPE_VIDEO:
3884 bandwidth += st->codec->bit_rate;
3890 stream->bandwidth = (bandwidth + 999) / 1000;
3894 /* add a codec and set the default parameters */
3895 static void add_codec(FFStream *stream, AVCodecContext *av)
3899 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3902 /* compute default parameters */
3903 switch(av->codec_type) {
3904 case AVMEDIA_TYPE_AUDIO:
3905 if (av->bit_rate == 0)
3906 av->bit_rate = 64000;
3907 if (av->sample_rate == 0)
3908 av->sample_rate = 22050;
3909 if (av->channels == 0)
3912 case AVMEDIA_TYPE_VIDEO:
3913 if (av->bit_rate == 0)
3914 av->bit_rate = 64000;
3915 if (av->time_base.num == 0){
3916 av->time_base.den = 5;
3917 av->time_base.num = 1;
3919 if (av->width == 0 || av->height == 0) {
3923 /* Bitrate tolerance is less for streaming */
3924 if (av->bit_rate_tolerance == 0)
3925 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3926 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3931 if (av->max_qdiff == 0)
3933 av->qcompress = 0.5;
3936 if (!av->nsse_weight)
3937 av->nsse_weight = 8;
3939 av->frame_skip_cmp = FF_CMP_DCTMAX;
3941 av->me_method = ME_EPZS;
3942 av->rc_buffer_aggressivity = 1.0;
3945 av->rc_eq = av_strdup("tex^qComp");
3946 if (!av->i_quant_factor)
3947 av->i_quant_factor = -0.8;
3948 if (!av->b_quant_factor)
3949 av->b_quant_factor = 1.25;
3950 if (!av->b_quant_offset)
3951 av->b_quant_offset = 1.25;
3952 if (!av->rc_max_rate)
3953 av->rc_max_rate = av->bit_rate * 2;
3955 if (av->rc_max_rate && !av->rc_buffer_size) {
3956 av->rc_buffer_size = av->rc_max_rate;
3965 st = av_mallocz(sizeof(AVStream));
3968 st->codec = avcodec_alloc_context3(NULL);
3969 stream->streams[stream->nb_streams++] = st;
3970 memcpy(st->codec, av, sizeof(AVCodecContext));
3973 static enum AVCodecID opt_codec(const char *name, enum AVMediaType type)
3975 AVCodec *codec = avcodec_find_encoder_by_name(name);
3977 if (!codec || codec->type != type)
3978 return AV_CODEC_ID_NONE;
3982 static int ffserver_opt_default(const char *opt, const char *arg,
3983 AVCodecContext *avctx, int type)
3986 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3988 ret = av_opt_set(avctx, opt, arg, 0);
3992 static int ffserver_opt_preset(const char *arg,
3993 AVCodecContext *avctx, int type,
3994 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3997 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3999 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
4001 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
4002 codec ? codec->name : NULL))) {
4003 fprintf(stderr, "File for preset '%s' not found\n", arg);
4008 int e= fscanf(f, "%999[^\n]\n", line) - 1;
4009 if(line[0] == '#' && !e)
4011 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
4013 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
4017 if(!strcmp(tmp, "acodec")){
4018 *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
4019 }else if(!strcmp(tmp, "vcodec")){
4020 *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
4021 }else if(!strcmp(tmp, "scodec")){
4022 /* opt_subtitle_codec(tmp2); */
4023 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
4024 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4035 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4036 const char *mime_type)
4038 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4041 AVOutputFormat *stream_fmt;
4042 char stream_format_name[64];
4044 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4045 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4054 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4058 fprintf(stderr, "%s:%d: ", filename, line_num);
4059 vfprintf(stderr, fmt, vl);
4065 static int parse_ffconfig(const char *filename)
4072 int val, errors, line_num;
4073 FFStream **last_stream, *stream, *redirect;
4074 FFStream **last_feed, *feed, *s;
4075 AVCodecContext audio_enc, video_enc;
4076 enum AVCodecID audio_id, video_id;
4079 f = fopen(filename, "r");
4081 ret = AVERROR(errno);
4082 av_log(NULL, AV_LOG_ERROR, "Could not open the configuration file '%s'\n", filename);
4088 first_stream = NULL;
4089 last_stream = &first_stream;
4091 last_feed = &first_feed;
4095 audio_id = AV_CODEC_ID_NONE;
4096 video_id = AV_CODEC_ID_NONE;
4098 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4100 if (fgets(line, sizeof(line), f) == NULL)
4104 while (av_isspace(*p))
4106 if (*p == '\0' || *p == '#')
4109 get_arg(cmd, sizeof(cmd), &p);
4111 if (!av_strcasecmp(cmd, "Port")) {
4112 get_arg(arg, sizeof(arg), &p);
4114 if (val < 1 || val > 65536) {
4115 ERROR("Invalid_port: %s\n", arg);
4117 my_http_addr.sin_port = htons(val);
4118 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4119 get_arg(arg, sizeof(arg), &p);
4120 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4121 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4123 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4124 // do nothing here, its the default now
4125 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4126 get_arg(arg, sizeof(arg), &p);
4128 if (val < 1 || val > 65536) {
4129 ERROR("%s:%d: Invalid port: %s\n", arg);
4131 my_rtsp_addr.sin_port = htons(atoi(arg));
4132 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4133 get_arg(arg, sizeof(arg), &p);
4134 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4135 ERROR("Invalid host/IP address: %s\n", arg);
4137 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4138 get_arg(arg, sizeof(arg), &p);
4140 if (val < 1 || val > 65536) {
4141 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4143 nb_max_http_connections = val;
4144 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4145 get_arg(arg, sizeof(arg), &p);
4147 if (val < 1 || val > nb_max_http_connections) {
4148 ERROR("Invalid MaxClients: %s\n", arg);
4150 nb_max_connections = val;
4152 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4154 get_arg(arg, sizeof(arg), &p);
4155 llval = strtoll(arg, NULL, 10);
4156 if (llval < 10 || llval > 10000000) {
4157 ERROR("Invalid MaxBandwidth: %s\n", arg);
4159 max_bandwidth = llval;
4160 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4161 if (!ffserver_debug)
4162 get_arg(logfilename, sizeof(logfilename), &p);
4163 } else if (!av_strcasecmp(cmd, "<Feed")) {
4164 /*********************************************/
4165 /* Feed related options */
4167 if (stream || feed) {
4168 ERROR("Already in a tag\n");
4170 feed = av_mallocz(sizeof(FFStream));
4172 ret = AVERROR(ENOMEM);
4175 get_arg(feed->filename, sizeof(feed->filename), &p);
4176 q = strrchr(feed->filename, '>');
4180 for (s = first_feed; s; s = s->next) {
4181 if (!strcmp(feed->filename, s->filename)) {
4182 ERROR("Feed '%s' already registered\n", s->filename);
4186 feed->fmt = av_guess_format("ffm", NULL, NULL);
4187 /* default feed file */
4188 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4189 "/tmp/%s.ffm", feed->filename);
4190 feed->feed_max_size = 5 * 1024 * 1024;
4192 feed->feed = feed; /* self feeding :-) */
4194 /* add in stream list */
4195 *last_stream = feed;
4196 last_stream = &feed->next;
4197 /* add in feed list */
4199 last_feed = &feed->next_feed;
4201 } else if (!av_strcasecmp(cmd, "Launch")) {
4205 feed->child_argv = av_mallocz(64 * sizeof(char *));
4206 if (!feed->child_argv) {
4207 ret = AVERROR(ENOMEM);
4210 for (i = 0; i < 62; i++) {
4211 get_arg(arg, sizeof(arg), &p);
4215 feed->child_argv[i] = av_strdup(arg);
4216 if (!feed->child_argv[i]) {
4217 ret = AVERROR(ENOMEM);
4222 feed->child_argv[i] =
4223 av_asprintf("http://%s:%d/%s",
4224 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4225 inet_ntoa(my_http_addr.sin_addr), ntohs(my_http_addr.sin_port),
4227 if (!feed->child_argv[i]) {
4228 ret = AVERROR(ENOMEM);
4232 } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
4234 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4235 feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile");
4236 } else if (stream) {
4237 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4239 } else if (!av_strcasecmp(cmd, "Truncate")) {
4241 get_arg(arg, sizeof(arg), &p);
4242 /* assume Truncate is true in case no argument is specified */
4246 av_log(NULL, AV_LOG_WARNING,
4247 "Truncate N syntax in configuration file is deprecated, "
4248 "use Truncate alone with no arguments\n");
4249 feed->truncate = strtod(arg, NULL);
4252 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4257 get_arg(arg, sizeof(arg), &p);
4259 fsize = strtod(p1, &p1);
4260 switch(av_toupper(*p1)) {
4265 fsize *= 1024 * 1024;
4268 fsize *= 1024 * 1024 * 1024;
4271 feed->feed_max_size = (int64_t)fsize;
4272 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4273 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4276 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4278 ERROR("No corresponding <Feed> for </Feed>\n");
4281 } else if (!av_strcasecmp(cmd, "<Stream")) {
4282 /*********************************************/
4283 /* Stream related options */
4285 if (stream || feed) {
4286 ERROR("Already in a tag\n");
4289 stream = av_mallocz(sizeof(FFStream));
4291 ret = AVERROR(ENOMEM);
4294 get_arg(stream->filename, sizeof(stream->filename), &p);
4295 q = strrchr(stream->filename, '>');
4299 for (s = first_stream; s; s = s->next) {
4300 if (!strcmp(stream->filename, s->filename)) {
4301 ERROR("Stream '%s' already registered\n", s->filename);
4305 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4306 avcodec_get_context_defaults3(&video_enc, NULL);
4307 avcodec_get_context_defaults3(&audio_enc, NULL);
4309 audio_id = AV_CODEC_ID_NONE;
4310 video_id = AV_CODEC_ID_NONE;
4312 audio_id = stream->fmt->audio_codec;
4313 video_id = stream->fmt->video_codec;
4316 *last_stream = stream;
4317 last_stream = &stream->next;
4319 } else if (!av_strcasecmp(cmd, "Feed")) {
4320 get_arg(arg, sizeof(arg), &p);
4325 while (sfeed != NULL) {
4326 if (!strcmp(sfeed->filename, arg))
4328 sfeed = sfeed->next_feed;
4331 ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg, stream->filename);
4333 stream->feed = sfeed;
4335 } else if (!av_strcasecmp(cmd, "Format")) {
4336 get_arg(arg, sizeof(arg), &p);
4338 if (!strcmp(arg, "status")) {
4339 stream->stream_type = STREAM_TYPE_STATUS;
4342 stream->stream_type = STREAM_TYPE_LIVE;
4343 /* jpeg cannot be used here, so use single frame jpeg */
4344 if (!strcmp(arg, "jpeg"))
4345 strcpy(arg, "mjpeg");
4346 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4348 ERROR("Unknown Format: %s\n", arg);
4352 audio_id = stream->fmt->audio_codec;
4353 video_id = stream->fmt->video_codec;
4356 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4357 get_arg(arg, sizeof(arg), &p);
4359 stream->ifmt = av_find_input_format(arg);
4360 if (!stream->ifmt) {
4361 ERROR("Unknown input format: %s\n", arg);
4364 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4365 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4366 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4368 ERROR("FaviconURL only permitted for status streams\n");
4370 } else if (!av_strcasecmp(cmd, "Author")) {
4372 get_arg(stream->author, sizeof(stream->author), &p);
4373 } else if (!av_strcasecmp(cmd, "Comment")) {
4375 get_arg(stream->comment, sizeof(stream->comment), &p);
4376 } else if (!av_strcasecmp(cmd, "Copyright")) {
4378 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4379 } else if (!av_strcasecmp(cmd, "Title")) {
4381 get_arg(stream->title, sizeof(stream->title), &p);
4382 } else if (!av_strcasecmp(cmd, "Preroll")) {
4383 get_arg(arg, sizeof(arg), &p);
4385 stream->prebuffer = atof(arg) * 1000;
4386 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4388 stream->send_on_key = 1;
4389 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4390 get_arg(arg, sizeof(arg), &p);
4391 audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO);
4392 if (audio_id == AV_CODEC_ID_NONE) {
4393 ERROR("Unknown AudioCodec: %s\n", arg);
4395 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4396 get_arg(arg, sizeof(arg), &p);
4397 video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO);
4398 if (video_id == AV_CODEC_ID_NONE) {
4399 ERROR("Unknown VideoCodec: %s\n", arg);
4401 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4402 get_arg(arg, sizeof(arg), &p);
4404 stream->max_time = atof(arg) * 1000;
4405 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4406 get_arg(arg, sizeof(arg), &p);
4408 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4409 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4410 get_arg(arg, sizeof(arg), &p);
4412 audio_enc.channels = atoi(arg);
4413 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4414 get_arg(arg, sizeof(arg), &p);
4416 audio_enc.sample_rate = atoi(arg);
4417 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4419 int minrate, maxrate;
4421 get_arg(arg, sizeof(arg), &p);
4423 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4424 video_enc.rc_min_rate = minrate * 1000;
4425 video_enc.rc_max_rate = maxrate * 1000;
4427 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4430 } else if (!av_strcasecmp(cmd, "Debug")) {
4432 get_arg(arg, sizeof(arg), &p);
4433 video_enc.debug = strtol(arg,0,0);
4435 } else if (!av_strcasecmp(cmd, "Strict")) {
4437 get_arg(arg, sizeof(arg), &p);
4438 video_enc.strict_std_compliance = atoi(arg);
4440 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4442 get_arg(arg, sizeof(arg), &p);
4443 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4445 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4447 get_arg(arg, sizeof(arg), &p);
4448 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4450 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4451 get_arg(arg, sizeof(arg), &p);
4453 video_enc.bit_rate = atoi(arg) * 1000;
4455 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4456 get_arg(arg, sizeof(arg), &p);
4458 ret = av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4460 ERROR("Invalid video size '%s'\n", arg);
4462 if ((video_enc.width % 16) != 0 ||
4463 (video_enc.height % 16) != 0) {
4464 ERROR("Image size must be a multiple of 16\n");
4468 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4469 get_arg(arg, sizeof(arg), &p);
4471 AVRational frame_rate;
4472 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4473 ERROR("Incorrect frame rate: %s\n", arg);
4475 video_enc.time_base.num = frame_rate.den;
4476 video_enc.time_base.den = frame_rate.num;
4479 } else if (!av_strcasecmp(cmd, "PixelFormat")) {
4480 get_arg(arg, sizeof(arg), &p);
4482 video_enc.pix_fmt = av_get_pix_fmt(arg);
4483 if (video_enc.pix_fmt == AV_PIX_FMT_NONE) {
4484 ERROR("Unknown pixel format: %s\n", arg);
4487 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4488 get_arg(arg, sizeof(arg), &p);
4490 video_enc.gop_size = atoi(arg);
4491 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4493 video_enc.gop_size = 1;
4494 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4496 video_enc.mb_decision = FF_MB_DECISION_BITS;
4497 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4499 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4500 video_enc.flags |= CODEC_FLAG_4MV;
4502 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4503 !av_strcasecmp(cmd, "AVOptionAudio")) {
4505 AVCodecContext *avctx;
4507 get_arg(arg, sizeof(arg), &p);
4508 get_arg(arg2, sizeof(arg2), &p);
4509 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4511 type = AV_OPT_FLAG_VIDEO_PARAM;
4514 type = AV_OPT_FLAG_AUDIO_PARAM;
4516 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4517 ERROR("Error setting %s option to %s %s\n", cmd, arg, arg2);
4519 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4520 !av_strcasecmp(cmd, "AVPresetAudio")) {
4521 AVCodecContext *avctx;
4523 get_arg(arg, sizeof(arg), &p);
4524 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4526 video_enc.codec_id = video_id;
4527 type = AV_OPT_FLAG_VIDEO_PARAM;
4530 audio_enc.codec_id = audio_id;
4531 type = AV_OPT_FLAG_AUDIO_PARAM;
4533 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4534 ERROR("AVPreset error: %s\n", arg);
4536 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4537 get_arg(arg, sizeof(arg), &p);
4538 if ((strlen(arg) == 4) && stream)
4539 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4540 } else if (!av_strcasecmp(cmd, "BitExact")) {
4542 video_enc.flags |= CODEC_FLAG_BITEXACT;
4543 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4545 video_enc.dct_algo = FF_DCT_FASTINT;
4546 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4548 video_enc.idct_algo = FF_IDCT_SIMPLE;
4549 } else if (!av_strcasecmp(cmd, "Qscale")) {
4550 get_arg(arg, sizeof(arg), &p);
4552 video_enc.flags |= CODEC_FLAG_QSCALE;
4553 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4555 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4556 get_arg(arg, sizeof(arg), &p);
4558 video_enc.max_qdiff = atoi(arg);
4559 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4560 ERROR("VideoQDiff out of range\n");
4563 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4564 get_arg(arg, sizeof(arg), &p);
4566 video_enc.qmax = atoi(arg);
4567 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4568 ERROR("VideoQMax out of range\n");
4571 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4572 get_arg(arg, sizeof(arg), &p);
4574 video_enc.qmin = atoi(arg);
4575 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4576 ERROR("VideoQMin out of range\n");
4579 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4580 get_arg(arg, sizeof(arg), &p);
4582 video_enc.lumi_masking = atof(arg);
4583 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4584 get_arg(arg, sizeof(arg), &p);
4586 video_enc.dark_masking = atof(arg);
4587 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4588 video_id = AV_CODEC_ID_NONE;
4589 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4590 audio_id = AV_CODEC_ID_NONE;
4591 } else if (!av_strcasecmp(cmd, "ACL")) {
4592 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4593 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4595 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4597 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4598 get_arg(arg, sizeof(arg), &p);
4600 av_freep(&stream->rtsp_option);
4601 stream->rtsp_option = av_strdup(arg);
4603 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4604 get_arg(arg, sizeof(arg), &p);
4606 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4607 ERROR("Invalid host/IP address: %s\n", arg);
4609 stream->is_multicast = 1;
4610 stream->loop = 1; /* default is looping */
4612 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4613 get_arg(arg, sizeof(arg), &p);
4615 stream->multicast_port = atoi(arg);
4616 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4617 get_arg(arg, sizeof(arg), &p);
4619 stream->multicast_ttl = atoi(arg);
4620 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4623 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4625 ERROR("No corresponding <Stream> for </Stream>\n");
4627 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4628 if (audio_id != AV_CODEC_ID_NONE) {
4629 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4630 audio_enc.codec_id = audio_id;
4631 add_codec(stream, &audio_enc);
4633 if (video_id != AV_CODEC_ID_NONE) {
4634 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4635 video_enc.codec_id = video_id;
4636 add_codec(stream, &video_enc);
4641 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4642 /*********************************************/
4644 if (stream || feed || redirect) {
4645 ERROR("Already in a tag\n");
4647 redirect = av_mallocz(sizeof(FFStream));
4649 ret = AVERROR(ENOMEM);
4652 *last_stream = redirect;
4653 last_stream = &redirect->next;
4655 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4656 q = strrchr(redirect->filename, '>');
4659 redirect->stream_type = STREAM_TYPE_REDIRECT;
4661 } else if (!av_strcasecmp(cmd, "URL")) {
4663 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4664 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4666 ERROR("No corresponding <Redirect> for </Redirect>\n");
4668 if (!redirect->feed_filename[0]) {
4669 ERROR("No URL found for <Redirect>\n");
4673 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4674 ERROR("Loadable modules no longer supported\n");
4676 ERROR("Incorrect keyword: '%s'\n", cmd);
4686 return AVERROR(EINVAL);
4691 static void handle_child_exit(int sig)
4696 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4699 for (feed = first_feed; feed; feed = feed->next) {
4700 if (feed->pid == pid) {
4701 int uptime = time(0) - feed->pid_start;
4704 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4707 /* Turn off any more restarts */
4708 feed->child_argv = 0;
4713 need_to_start_children = 1;
4716 static void opt_debug(void)
4719 logfilename[0] = '-';
4722 void show_help_default(const char *opt, const char *arg)
4724 printf("usage: ffserver [options]\n"
4725 "Hyper fast multi format Audio/Video streaming server\n");
4727 show_help_options(options, "Main options:", 0, 0, 0);
4730 static const OptionDef options[] = {
4731 #include "cmdutils_common_opts.h"
4732 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4733 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4734 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4738 int main(int argc, char **argv)
4740 struct sigaction sigact = { { 0 } };
4743 config_filename = av_strdup("/etc/ffserver.conf");
4745 parse_loglevel(argc, argv, options);
4747 avformat_network_init();
4749 show_banner(argc, argv, options);
4751 my_program_name = argv[0];
4753 parse_options(NULL, argc, argv, options, NULL);
4755 unsetenv("http_proxy"); /* Kill the http_proxy */
4757 av_lfg_init(&random_state, av_get_random_seed());
4759 sigact.sa_handler = handle_child_exit;
4760 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4761 sigaction(SIGCHLD, &sigact, 0);
4763 if ((ret = parse_ffconfig(config_filename)) < 0) {
4764 fprintf(stderr, "Error reading configuration file '%s': %s\n",
4765 config_filename, av_err2str(ret));
4768 av_freep(&config_filename);
4770 /* open log file if needed */
4771 if (logfilename[0] != '\0') {
4772 if (!strcmp(logfilename, "-"))
4775 logfile = fopen(logfilename, "a");
4776 av_log_set_callback(http_av_log);
4779 build_file_streams();
4781 build_feed_streams();
4783 compute_bandwidth();
4786 signal(SIGPIPE, SIG_IGN);
4788 if (http_server() < 0) {
4789 http_log("Could not start server\n");