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 (av_write_frame(ctx, &pkt) < 0) {
2459 http_log("Error writing frame to output\n");
2460 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2463 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2464 c->cur_frame_bytes = len;
2465 c->buffer_ptr = c->pb_buffer;
2466 c->buffer_end = c->pb_buffer + len;
2468 codec->frame_number++;
2470 av_free_packet(&pkt);
2474 av_free_packet(&pkt);
2479 case HTTPSTATE_SEND_DATA_TRAILER:
2480 /* last packet test ? */
2481 if (c->last_packet_sent || c->is_packetized)
2484 /* prepare header */
2485 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2486 /* XXX: potential leak */
2489 c->fmt_ctx.pb->seekable = 0;
2490 av_write_trailer(ctx);
2491 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2492 c->buffer_ptr = c->pb_buffer;
2493 c->buffer_end = c->pb_buffer + len;
2495 c->last_packet_sent = 1;
2501 /* should convert the format at the same time */
2502 /* send data starting at c->buffer_ptr to the output connection
2503 (either UDP or TCP connection) */
2504 static int http_send_data(HTTPContext *c)
2509 if (c->buffer_ptr >= c->buffer_end) {
2510 ret = http_prepare_data(c);
2514 /* state change requested */
2517 if (c->is_packetized) {
2518 /* RTP data output */
2519 len = c->buffer_end - c->buffer_ptr;
2521 /* fail safe - should never happen */
2523 c->buffer_ptr = c->buffer_end;
2526 len = (c->buffer_ptr[0] << 24) |
2527 (c->buffer_ptr[1] << 16) |
2528 (c->buffer_ptr[2] << 8) |
2530 if (len > (c->buffer_end - c->buffer_ptr))
2532 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2533 /* nothing to send yet: we can wait */
2537 c->data_count += len;
2538 update_datarate(&c->datarate, c->data_count);
2540 c->stream->bytes_served += len;
2542 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2543 /* RTP packets are sent inside the RTSP TCP connection */
2545 int interleaved_index, size;
2547 HTTPContext *rtsp_c;
2550 /* if no RTSP connection left, error */
2553 /* if already sending something, then wait. */
2554 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2556 if (avio_open_dyn_buf(&pb) < 0)
2558 interleaved_index = c->packet_stream_index * 2;
2559 /* RTCP packets are sent at odd indexes */
2560 if (c->buffer_ptr[1] == 200)
2561 interleaved_index++;
2562 /* write RTSP TCP header */
2564 header[1] = interleaved_index;
2565 header[2] = len >> 8;
2567 avio_write(pb, header, 4);
2568 /* write RTP packet data */
2570 avio_write(pb, c->buffer_ptr, len);
2571 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2572 /* prepare asynchronous TCP sending */
2573 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2574 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2575 c->buffer_ptr += len;
2577 /* send everything we can NOW */
2578 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2579 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2581 rtsp_c->packet_buffer_ptr += len;
2582 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2583 /* if we could not send all the data, we will
2584 send it later, so a new state is needed to
2585 "lock" the RTSP TCP connection */
2586 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2589 /* all data has been sent */
2590 av_freep(&c->packet_buffer);
2592 /* send RTP packet directly in UDP */
2594 ffurl_write(c->rtp_handles[c->packet_stream_index],
2595 c->buffer_ptr, len);
2596 c->buffer_ptr += len;
2597 /* here we continue as we can send several packets per 10 ms slot */
2600 /* TCP data output */
2601 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2603 if (ff_neterrno() != AVERROR(EAGAIN) &&
2604 ff_neterrno() != AVERROR(EINTR))
2605 /* error : close connection */
2610 c->buffer_ptr += len;
2612 c->data_count += len;
2613 update_datarate(&c->datarate, c->data_count);
2615 c->stream->bytes_served += len;
2623 static int http_start_receive_data(HTTPContext *c)
2628 if (c->stream->feed_opened) {
2629 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2630 return AVERROR(EINVAL);
2633 /* Don't permit writing to this one */
2634 if (c->stream->readonly) {
2635 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2636 return AVERROR(EINVAL);
2640 fd = open(c->stream->feed_filename, O_RDWR);
2642 ret = AVERROR(errno);
2643 http_log("Could not open feed file '%s':%s \n",
2644 c->stream->feed_filename, strerror(errno));
2649 if (c->stream->truncate) {
2650 /* truncate feed file */
2651 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2652 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2653 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2654 ret = AVERROR(errno);
2655 http_log("Error truncating feed file '%s': %s\n",
2656 c->stream->feed_filename, strerror(errno));
2660 ret = ffm_read_write_index(fd);
2662 http_log("Error reading write index from feed file '%s': %s\n",
2663 c->stream->feed_filename, strerror(errno));
2666 c->stream->feed_write_index = ret;
2670 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2671 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2672 lseek(fd, 0, SEEK_SET);
2674 /* init buffer input */
2675 c->buffer_ptr = c->buffer;
2676 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2677 c->stream->feed_opened = 1;
2678 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2682 static int http_receive_data(HTTPContext *c)
2685 int len, loop_run = 0;
2687 while (c->chunked_encoding && !c->chunk_size &&
2688 c->buffer_end > c->buffer_ptr) {
2689 /* read chunk header, if present */
2690 len = recv(c->fd, c->buffer_ptr, 1, 0);
2693 if (ff_neterrno() != AVERROR(EAGAIN) &&
2694 ff_neterrno() != AVERROR(EINTR))
2695 /* error : close connection */
2698 } else if (len == 0) {
2699 /* end of connection : close it */
2701 } else if (c->buffer_ptr - c->buffer >= 2 &&
2702 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2703 c->chunk_size = strtol(c->buffer, 0, 16);
2704 if (c->chunk_size == 0) // end of stream
2706 c->buffer_ptr = c->buffer;
2708 } else if (++loop_run > 10) {
2709 /* no chunk header, abort */
2716 if (c->buffer_end > c->buffer_ptr) {
2717 len = recv(c->fd, c->buffer_ptr,
2718 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2720 if (ff_neterrno() != AVERROR(EAGAIN) &&
2721 ff_neterrno() != AVERROR(EINTR))
2722 /* error : close connection */
2724 } else if (len == 0)
2725 /* end of connection : close it */
2728 c->chunk_size -= len;
2729 c->buffer_ptr += len;
2730 c->data_count += len;
2731 update_datarate(&c->datarate, c->data_count);
2735 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2736 if (c->buffer[0] != 'f' ||
2737 c->buffer[1] != 'm') {
2738 http_log("Feed stream has become desynchronized -- disconnecting\n");
2743 if (c->buffer_ptr >= c->buffer_end) {
2744 FFStream *feed = c->stream;
2745 /* a packet has been received : write it in the store, except
2747 if (c->data_count > FFM_PACKET_SIZE) {
2748 /* XXX: use llseek or url_seek */
2749 lseek(c->feed_fd, feed->feed_write_index, SEEK_SET);
2750 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2751 http_log("Error writing to feed file: %s\n", strerror(errno));
2755 feed->feed_write_index += FFM_PACKET_SIZE;
2756 /* update file size */
2757 if (feed->feed_write_index > c->stream->feed_size)
2758 feed->feed_size = feed->feed_write_index;
2760 /* handle wrap around if max file size reached */
2761 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2762 feed->feed_write_index = FFM_PACKET_SIZE;
2765 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2766 http_log("Error writing index to feed file: %s\n", strerror(errno));
2770 /* wake up any waiting connections */
2771 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2772 if (c1->state == HTTPSTATE_WAIT_FEED &&
2773 c1->stream->feed == c->stream->feed)
2774 c1->state = HTTPSTATE_SEND_DATA;
2777 /* We have a header in our hands that contains useful data */
2778 AVFormatContext *s = avformat_alloc_context();
2780 AVInputFormat *fmt_in;
2786 /* use feed output format name to find corresponding input format */
2787 fmt_in = av_find_input_format(feed->fmt->name);
2791 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2792 0, NULL, NULL, NULL, NULL);
2796 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2801 /* Now we have the actual streams */
2802 if (s->nb_streams != feed->nb_streams) {
2803 avformat_close_input(&s);
2805 http_log("Feed '%s' stream number does not match registered feed\n",
2806 c->stream->feed_filename);
2810 for (i = 0; i < s->nb_streams; i++) {
2811 AVStream *fst = feed->streams[i];
2812 AVStream *st = s->streams[i];
2813 avcodec_copy_context(fst->codec, st->codec);
2816 avformat_close_input(&s);
2819 c->buffer_ptr = c->buffer;
2824 c->stream->feed_opened = 0;
2826 /* wake up any waiting connections to stop waiting for feed */
2827 for(c1 = first_http_ctx; c1 != NULL; c1 = c1->next) {
2828 if (c1->state == HTTPSTATE_WAIT_FEED &&
2829 c1->stream->feed == c->stream->feed)
2830 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2835 /********************************************************************/
2838 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2845 switch(error_number) {
2846 case RTSP_STATUS_OK:
2849 case RTSP_STATUS_METHOD:
2850 str = "Method Not Allowed";
2852 case RTSP_STATUS_BANDWIDTH:
2853 str = "Not Enough Bandwidth";
2855 case RTSP_STATUS_SESSION:
2856 str = "Session Not Found";
2858 case RTSP_STATUS_STATE:
2859 str = "Method Not Valid in This State";
2861 case RTSP_STATUS_AGGREGATE:
2862 str = "Aggregate operation not allowed";
2864 case RTSP_STATUS_ONLY_AGGREGATE:
2865 str = "Only aggregate operation allowed";
2867 case RTSP_STATUS_TRANSPORT:
2868 str = "Unsupported transport";
2870 case RTSP_STATUS_INTERNAL:
2871 str = "Internal Server Error";
2873 case RTSP_STATUS_SERVICE:
2874 str = "Service Unavailable";
2876 case RTSP_STATUS_VERSION:
2877 str = "RTSP Version not supported";
2880 str = "Unknown Error";
2884 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2885 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2887 /* output GMT time */
2890 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2891 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2894 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2896 rtsp_reply_header(c, error_number);
2897 avio_printf(c->pb, "\r\n");
2900 static int rtsp_parse_request(HTTPContext *c)
2902 const char *p, *p1, *p2;
2908 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2910 c->buffer_ptr[0] = '\0';
2913 get_word(cmd, sizeof(cmd), &p);
2914 get_word(url, sizeof(url), &p);
2915 get_word(protocol, sizeof(protocol), &p);
2917 av_strlcpy(c->method, cmd, sizeof(c->method));
2918 av_strlcpy(c->url, url, sizeof(c->url));
2919 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2921 if (avio_open_dyn_buf(&c->pb) < 0) {
2922 /* XXX: cannot do more */
2923 c->pb = NULL; /* safety */
2927 /* check version name */
2928 if (strcmp(protocol, "RTSP/1.0") != 0) {
2929 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2933 /* parse each header line */
2934 /* skip to next line */
2935 while (*p != '\n' && *p != '\0')
2939 while (*p != '\0') {
2940 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2944 if (p2 > p && p2[-1] == '\r')
2946 /* skip empty line */
2950 if (len > sizeof(line) - 1)
2951 len = sizeof(line) - 1;
2952 memcpy(line, p, len);
2954 ff_rtsp_parse_line(header, line, NULL, NULL);
2958 /* handle sequence number */
2959 c->seq = header->seq;
2961 if (!strcmp(cmd, "DESCRIBE"))
2962 rtsp_cmd_describe(c, url);
2963 else if (!strcmp(cmd, "OPTIONS"))
2964 rtsp_cmd_options(c, url);
2965 else if (!strcmp(cmd, "SETUP"))
2966 rtsp_cmd_setup(c, url, header);
2967 else if (!strcmp(cmd, "PLAY"))
2968 rtsp_cmd_play(c, url, header);
2969 else if (!strcmp(cmd, "PAUSE"))
2970 rtsp_cmd_pause(c, url, header);
2971 else if (!strcmp(cmd, "TEARDOWN"))
2972 rtsp_cmd_teardown(c, url, header);
2974 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2977 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2978 c->pb = NULL; /* safety */
2980 /* XXX: cannot do more */
2983 c->buffer_ptr = c->pb_buffer;
2984 c->buffer_end = c->pb_buffer + len;
2985 c->state = RTSPSTATE_SEND_REPLY;
2989 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2990 struct in_addr my_ip)
2992 AVFormatContext *avc;
2993 AVStream *avs = NULL;
2994 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2997 avc = avformat_alloc_context();
2998 if (avc == NULL || !rtp_format) {
3001 avc->oformat = rtp_format;
3002 av_dict_set(&avc->metadata, "title",
3003 stream->title[0] ? stream->title : "No Title", 0);
3004 avc->nb_streams = stream->nb_streams;
3005 if (stream->is_multicast) {
3006 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
3007 inet_ntoa(stream->multicast_ip),
3008 stream->multicast_port, stream->multicast_ttl);
3010 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
3013 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
3014 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
3016 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
3017 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
3020 for(i = 0; i < stream->nb_streams; i++) {
3021 avc->streams[i] = &avs[i];
3022 avc->streams[i]->codec = stream->streams[i]->codec;
3024 *pbuffer = av_mallocz(2048);
3025 av_sdp_create(&avc, 1, *pbuffer, 2048);
3028 av_free(avc->streams);
3029 av_dict_free(&avc->metadata);
3033 return strlen(*pbuffer);
3036 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3038 // rtsp_reply_header(c, RTSP_STATUS_OK);
3039 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3040 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3041 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3042 avio_printf(c->pb, "\r\n");
3045 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3053 struct sockaddr_in my_addr;
3055 /* find which url is asked */
3056 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3061 for(stream = first_stream; stream != NULL; stream = stream->next) {
3062 if (!stream->is_feed &&
3063 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3064 !strcmp(path, stream->filename)) {
3068 /* no stream found */
3069 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3073 /* prepare the media description in sdp format */
3075 /* get the host IP */
3076 len = sizeof(my_addr);
3077 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3078 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3079 if (content_length < 0) {
3080 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3083 rtsp_reply_header(c, RTSP_STATUS_OK);
3084 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3085 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3086 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3087 avio_printf(c->pb, "\r\n");
3088 avio_write(c->pb, content, content_length);
3092 static HTTPContext *find_rtp_session(const char *session_id)
3096 if (session_id[0] == '\0')
3099 for(c = first_http_ctx; c != NULL; c = c->next) {
3100 if (!strcmp(c->session_id, session_id))
3106 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3108 RTSPTransportField *th;
3111 for(i=0;i<h->nb_transports;i++) {
3112 th = &h->transports[i];
3113 if (th->lower_transport == lower_transport)
3119 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3120 RTSPMessageHeader *h)
3123 int stream_index, rtp_port, rtcp_port;
3128 RTSPTransportField *th;
3129 struct sockaddr_in dest_addr;
3130 RTSPActionServerSetup setup;
3132 /* find which url is asked */
3133 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3138 /* now check each stream */
3139 for(stream = first_stream; stream != NULL; stream = stream->next) {
3140 if (!stream->is_feed &&
3141 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3142 /* accept aggregate filenames only if single stream */
3143 if (!strcmp(path, stream->filename)) {
3144 if (stream->nb_streams != 1) {
3145 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3152 for(stream_index = 0; stream_index < stream->nb_streams;
3154 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3155 stream->filename, stream_index);
3156 if (!strcmp(path, buf))
3161 /* no stream found */
3162 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3166 /* generate session id if needed */
3167 if (h->session_id[0] == '\0') {
3168 unsigned random0 = av_lfg_get(&random_state);
3169 unsigned random1 = av_lfg_get(&random_state);
3170 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3174 /* find rtp session, and create it if none found */
3175 rtp_c = find_rtp_session(h->session_id);
3177 /* always prefer UDP */
3178 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3180 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3182 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3187 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3188 th->lower_transport);
3190 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3194 /* open input stream */
3195 if (open_input_stream(rtp_c, "") < 0) {
3196 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3201 /* test if stream is OK (test needed because several SETUP needs
3202 to be done for a given file) */
3203 if (rtp_c->stream != stream) {
3204 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3208 /* test if stream is already set up */
3209 if (rtp_c->rtp_ctx[stream_index]) {
3210 rtsp_reply_error(c, RTSP_STATUS_STATE);
3214 /* check transport */
3215 th = find_transport(h, rtp_c->rtp_protocol);
3216 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3217 th->client_port_min <= 0)) {
3218 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3222 /* setup default options */
3223 setup.transport_option[0] = '\0';
3224 dest_addr = rtp_c->from_addr;
3225 dest_addr.sin_port = htons(th->client_port_min);
3228 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3229 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3233 /* now everything is OK, so we can send the connection parameters */
3234 rtsp_reply_header(c, RTSP_STATUS_OK);
3236 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3238 switch(rtp_c->rtp_protocol) {
3239 case RTSP_LOWER_TRANSPORT_UDP:
3240 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3241 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3242 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3243 "client_port=%d-%d;server_port=%d-%d",
3244 th->client_port_min, th->client_port_max,
3245 rtp_port, rtcp_port);
3247 case RTSP_LOWER_TRANSPORT_TCP:
3248 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3249 stream_index * 2, stream_index * 2 + 1);
3254 if (setup.transport_option[0] != '\0')
3255 avio_printf(c->pb, ";%s", setup.transport_option);
3256 avio_printf(c->pb, "\r\n");
3259 avio_printf(c->pb, "\r\n");
3263 /* find an rtp connection by using the session ID. Check consistency
3265 static HTTPContext *find_rtp_session_with_url(const char *url,
3266 const char *session_id)
3274 rtp_c = find_rtp_session(session_id);
3278 /* find which url is asked */
3279 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3283 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3284 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3285 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3286 rtp_c->stream->filename, s);
3287 if(!strncmp(path, buf, sizeof(buf))) {
3288 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3293 if (len > 0 && path[len - 1] == '/' &&
3294 !strncmp(path, rtp_c->stream->filename, len - 1))
3299 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3303 rtp_c = find_rtp_session_with_url(url, h->session_id);
3305 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3309 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3310 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3311 rtp_c->state != HTTPSTATE_READY) {
3312 rtsp_reply_error(c, RTSP_STATUS_STATE);
3316 rtp_c->state = HTTPSTATE_SEND_DATA;
3318 /* now everything is OK, so we can send the connection parameters */
3319 rtsp_reply_header(c, RTSP_STATUS_OK);
3321 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3322 avio_printf(c->pb, "\r\n");
3325 static void rtsp_cmd_pause(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3329 rtp_c = find_rtp_session_with_url(url, h->session_id);
3331 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3335 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3336 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3337 rtsp_reply_error(c, RTSP_STATUS_STATE);
3341 rtp_c->state = HTTPSTATE_READY;
3342 rtp_c->first_pts = AV_NOPTS_VALUE;
3343 /* now everything is OK, so we can send the connection parameters */
3344 rtsp_reply_header(c, RTSP_STATUS_OK);
3346 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3347 avio_printf(c->pb, "\r\n");
3350 static void rtsp_cmd_teardown(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3354 rtp_c = find_rtp_session_with_url(url, h->session_id);
3356 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3360 /* now everything is OK, so we can send the connection parameters */
3361 rtsp_reply_header(c, RTSP_STATUS_OK);
3363 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3364 avio_printf(c->pb, "\r\n");
3366 /* abort the session */
3367 close_connection(rtp_c);
3371 /********************************************************************/
3374 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3375 FFStream *stream, const char *session_id,
3376 enum RTSPLowerTransport rtp_protocol)
3378 HTTPContext *c = NULL;
3379 const char *proto_str;
3381 /* XXX: should output a warning page when coming
3382 close to the connection limit */
3383 if (nb_connections >= nb_max_connections)
3386 /* add a new connection */
3387 c = av_mallocz(sizeof(HTTPContext));
3392 c->poll_entry = NULL;
3393 c->from_addr = *from_addr;
3394 c->buffer_size = IOBUFFER_INIT_SIZE;
3395 c->buffer = av_malloc(c->buffer_size);
3400 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3401 c->state = HTTPSTATE_READY;
3402 c->is_packetized = 1;
3403 c->rtp_protocol = rtp_protocol;
3405 /* protocol is shown in statistics */
3406 switch(c->rtp_protocol) {
3407 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3408 proto_str = "MCAST";
3410 case RTSP_LOWER_TRANSPORT_UDP:
3413 case RTSP_LOWER_TRANSPORT_TCP:
3420 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3421 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3423 current_bandwidth += stream->bandwidth;
3425 c->next = first_http_ctx;
3437 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3438 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3440 static int rtp_new_av_stream(HTTPContext *c,
3441 int stream_index, struct sockaddr_in *dest_addr,
3442 HTTPContext *rtsp_c)
3444 AVFormatContext *ctx;
3447 URLContext *h = NULL;
3449 int max_packet_size;
3451 /* now we can open the relevant output stream */
3452 ctx = avformat_alloc_context();
3455 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3457 st = av_mallocz(sizeof(AVStream));
3460 ctx->nb_streams = 1;
3461 ctx->streams = av_mallocz(sizeof(AVStream *) * ctx->nb_streams);
3464 ctx->streams[0] = st;
3466 if (!c->stream->feed ||
3467 c->stream->feed == c->stream)
3468 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3471 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3473 st->priv_data = NULL;
3475 /* build destination RTP address */
3476 ipaddr = inet_ntoa(dest_addr->sin_addr);
3478 switch(c->rtp_protocol) {
3479 case RTSP_LOWER_TRANSPORT_UDP:
3480 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3483 /* XXX: also pass as parameter to function ? */
3484 if (c->stream->is_multicast) {
3486 ttl = c->stream->multicast_ttl;
3489 snprintf(ctx->filename, sizeof(ctx->filename),
3490 "rtp://%s:%d?multicast=1&ttl=%d",
3491 ipaddr, ntohs(dest_addr->sin_port), ttl);
3493 snprintf(ctx->filename, sizeof(ctx->filename),
3494 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3497 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3499 c->rtp_handles[stream_index] = h;
3500 max_packet_size = h->max_packet_size;
3502 case RTSP_LOWER_TRANSPORT_TCP:
3505 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3511 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3512 ipaddr, ntohs(dest_addr->sin_port),
3513 c->stream->filename, stream_index, c->protocol);
3515 /* normally, no packets should be output here, but the packet size may be checked */
3516 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3517 /* XXX: close stream */
3520 if (avformat_write_header(ctx, NULL) < 0) {
3527 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3530 c->rtp_ctx[stream_index] = ctx;
3534 /********************************************************************/
3535 /* ffserver initialization */
3537 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3541 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3544 fst = av_mallocz(sizeof(AVStream));
3548 fst->codec = avcodec_alloc_context3(NULL);
3549 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3550 if (codec->extradata_size) {
3551 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3552 memcpy(fst->codec->extradata, codec->extradata,
3553 codec->extradata_size);
3556 /* live streams must use the actual feed's codec since it may be
3557 * updated later to carry extradata needed by the streams.
3561 fst->priv_data = av_mallocz(sizeof(FeedData));
3562 fst->index = stream->nb_streams;
3563 avpriv_set_pts_info(fst, 33, 1, 90000);
3564 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3565 stream->streams[stream->nb_streams++] = fst;
3569 /* return the stream number in the feed */
3570 static int add_av_stream(FFStream *feed, AVStream *st)
3573 AVCodecContext *av, *av1;
3577 for(i=0;i<feed->nb_streams;i++) {
3578 st = feed->streams[i];
3580 if (av1->codec_id == av->codec_id &&
3581 av1->codec_type == av->codec_type &&
3582 av1->bit_rate == av->bit_rate) {
3584 switch(av->codec_type) {
3585 case AVMEDIA_TYPE_AUDIO:
3586 if (av1->channels == av->channels &&
3587 av1->sample_rate == av->sample_rate)
3590 case AVMEDIA_TYPE_VIDEO:
3591 if (av1->width == av->width &&
3592 av1->height == av->height &&
3593 av1->time_base.den == av->time_base.den &&
3594 av1->time_base.num == av->time_base.num &&
3595 av1->gop_size == av->gop_size)
3604 fst = add_av_stream1(feed, av, 0);
3607 return feed->nb_streams - 1;
3610 static void remove_stream(FFStream *stream)
3614 while (*ps != NULL) {
3622 /* specific mpeg4 handling : we extract the raw parameters */
3623 static void extract_mpeg4_header(AVFormatContext *infile)
3625 int mpeg4_count, i, size;
3630 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3633 for(i=0;i<infile->nb_streams;i++) {
3634 st = infile->streams[i];
3635 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3636 st->codec->extradata_size == 0) {
3643 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3644 while (mpeg4_count > 0) {
3645 if (av_read_frame(infile, &pkt) < 0)
3647 st = infile->streams[pkt.stream_index];
3648 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3649 st->codec->extradata_size == 0) {
3650 av_freep(&st->codec->extradata);
3651 /* fill extradata with the header */
3652 /* XXX: we make hard suppositions here ! */
3654 while (p < pkt.data + pkt.size - 4) {
3655 /* stop when vop header is found */
3656 if (p[0] == 0x00 && p[1] == 0x00 &&
3657 p[2] == 0x01 && p[3] == 0xb6) {
3658 size = p - pkt.data;
3659 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3660 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3661 st->codec->extradata_size = size;
3662 memcpy(st->codec->extradata, pkt.data, size);
3669 av_free_packet(&pkt);
3673 /* compute the needed AVStream for each file */
3674 static void build_file_streams(void)
3676 FFStream *stream, *stream_next;
3679 /* gather all streams */
3680 for(stream = first_stream; stream != NULL; stream = stream_next) {
3681 AVFormatContext *infile = NULL;
3682 stream_next = stream->next;
3683 if (stream->stream_type == STREAM_TYPE_LIVE &&
3685 /* the stream comes from a file */
3686 /* try to open the file */
3688 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3689 /* specific case : if transport stream output to RTP,
3690 we use a raw transport stream reader */
3691 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3694 if (!stream->feed_filename[0]) {
3695 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3699 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3700 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3701 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3702 /* remove stream (no need to spend more time on it) */
3704 remove_stream(stream);
3706 /* find all the AVStreams inside and reference them in
3708 if (avformat_find_stream_info(infile, NULL) < 0) {
3709 http_log("Could not find codec parameters from '%s'\n",
3710 stream->feed_filename);
3711 avformat_close_input(&infile);
3714 extract_mpeg4_header(infile);
3716 for(i=0;i<infile->nb_streams;i++)
3717 add_av_stream1(stream, infile->streams[i]->codec, 1);
3719 avformat_close_input(&infile);
3725 /* compute the needed AVStream for each feed */
3726 static void build_feed_streams(void)
3728 FFStream *stream, *feed;
3731 /* gather all streams */
3732 for(stream = first_stream; stream != NULL; stream = stream->next) {
3733 feed = stream->feed;
3735 if (stream->is_feed) {
3736 for(i=0;i<stream->nb_streams;i++)
3737 stream->feed_streams[i] = i;
3739 /* we handle a stream coming from a feed */
3740 for(i=0;i<stream->nb_streams;i++)
3741 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3746 /* create feed files if needed */
3747 for(feed = first_feed; feed != NULL; feed = feed->next_feed) {
3750 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3751 /* See if it matches */
3752 AVFormatContext *s = NULL;
3755 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3756 /* set buffer size */
3757 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3758 /* Now see if it matches */
3759 if (s->nb_streams == feed->nb_streams) {
3761 for(i=0;i<s->nb_streams;i++) {
3763 sf = feed->streams[i];
3766 if (sf->index != ss->index ||
3768 http_log("Index & Id do not match for stream %d (%s)\n",
3769 i, feed->feed_filename);
3772 AVCodecContext *ccf, *ccs;
3776 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3778 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3779 http_log("Codecs do not match for stream %d\n", i);
3781 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3782 http_log("Codec bitrates do not match for stream %d\n", i);
3784 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3785 if (CHECK_CODEC(time_base.den) ||
3786 CHECK_CODEC(time_base.num) ||
3787 CHECK_CODEC(width) ||
3788 CHECK_CODEC(height)) {
3789 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3792 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3793 if (CHECK_CODEC(sample_rate) ||
3794 CHECK_CODEC(channels) ||
3795 CHECK_CODEC(frame_size)) {
3796 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3800 http_log("Unknown codec type\n");
3808 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3809 feed->feed_filename, s->nb_streams, feed->nb_streams);
3811 avformat_close_input(&s);
3813 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3814 feed->feed_filename);
3817 if (feed->readonly) {
3818 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3819 feed->feed_filename);
3822 unlink(feed->feed_filename);
3825 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3826 AVFormatContext s1 = {0}, *s = &s1;
3828 if (feed->readonly) {
3829 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3830 feed->feed_filename);
3834 /* only write the header of the ffm file */
3835 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3836 http_log("Could not open output feed file '%s'\n",
3837 feed->feed_filename);
3840 s->oformat = feed->fmt;
3841 s->nb_streams = feed->nb_streams;
3842 s->streams = feed->streams;
3843 if (avformat_write_header(s, NULL) < 0) {
3844 http_log("Container doesn't support the required parameters\n");
3847 /* XXX: need better api */
3848 av_freep(&s->priv_data);
3851 /* get feed size and write index */
3852 fd = open(feed->feed_filename, O_RDONLY);
3854 http_log("Could not open output feed file '%s'\n",
3855 feed->feed_filename);
3859 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3860 feed->feed_size = lseek(fd, 0, SEEK_END);
3861 /* ensure that we do not wrap before the end of file */
3862 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3863 feed->feed_max_size = feed->feed_size;
3869 /* compute the bandwidth used by each stream */
3870 static void compute_bandwidth(void)
3876 for(stream = first_stream; stream != NULL; stream = stream->next) {
3878 for(i=0;i<stream->nb_streams;i++) {
3879 AVStream *st = stream->streams[i];
3880 switch(st->codec->codec_type) {
3881 case AVMEDIA_TYPE_AUDIO:
3882 case AVMEDIA_TYPE_VIDEO:
3883 bandwidth += st->codec->bit_rate;
3889 stream->bandwidth = (bandwidth + 999) / 1000;
3893 /* add a codec and set the default parameters */
3894 static void add_codec(FFStream *stream, AVCodecContext *av)
3898 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3901 /* compute default parameters */
3902 switch(av->codec_type) {
3903 case AVMEDIA_TYPE_AUDIO:
3904 if (av->bit_rate == 0)
3905 av->bit_rate = 64000;
3906 if (av->sample_rate == 0)
3907 av->sample_rate = 22050;
3908 if (av->channels == 0)
3911 case AVMEDIA_TYPE_VIDEO:
3912 if (av->bit_rate == 0)
3913 av->bit_rate = 64000;
3914 if (av->time_base.num == 0){
3915 av->time_base.den = 5;
3916 av->time_base.num = 1;
3918 if (av->width == 0 || av->height == 0) {
3922 /* Bitrate tolerance is less for streaming */
3923 if (av->bit_rate_tolerance == 0)
3924 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3925 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3930 if (av->max_qdiff == 0)
3932 av->qcompress = 0.5;
3935 if (!av->nsse_weight)
3936 av->nsse_weight = 8;
3938 av->frame_skip_cmp = FF_CMP_DCTMAX;
3940 av->me_method = ME_EPZS;
3941 av->rc_buffer_aggressivity = 1.0;
3944 av->rc_eq = av_strdup("tex^qComp");
3945 if (!av->i_quant_factor)
3946 av->i_quant_factor = -0.8;
3947 if (!av->b_quant_factor)
3948 av->b_quant_factor = 1.25;
3949 if (!av->b_quant_offset)
3950 av->b_quant_offset = 1.25;
3951 if (!av->rc_max_rate)
3952 av->rc_max_rate = av->bit_rate * 2;
3954 if (av->rc_max_rate && !av->rc_buffer_size) {
3955 av->rc_buffer_size = av->rc_max_rate;
3964 st = av_mallocz(sizeof(AVStream));
3967 st->codec = avcodec_alloc_context3(NULL);
3968 stream->streams[stream->nb_streams++] = st;
3969 memcpy(st->codec, av, sizeof(AVCodecContext));
3972 static enum AVCodecID opt_codec(const char *name, enum AVMediaType type)
3974 AVCodec *codec = avcodec_find_encoder_by_name(name);
3976 if (!codec || codec->type != type)
3977 return AV_CODEC_ID_NONE;
3981 static int ffserver_opt_default(const char *opt, const char *arg,
3982 AVCodecContext *avctx, int type)
3985 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3987 ret = av_opt_set(avctx, opt, arg, 0);
3991 static int ffserver_opt_preset(const char *arg,
3992 AVCodecContext *avctx, int type,
3993 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3996 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3998 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
4000 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
4001 codec ? codec->name : NULL))) {
4002 fprintf(stderr, "File for preset '%s' not found\n", arg);
4007 int e= fscanf(f, "%999[^\n]\n", line) - 1;
4008 if(line[0] == '#' && !e)
4010 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
4012 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
4016 if(!strcmp(tmp, "acodec")){
4017 *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
4018 }else if(!strcmp(tmp, "vcodec")){
4019 *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
4020 }else if(!strcmp(tmp, "scodec")){
4021 /* opt_subtitle_codec(tmp2); */
4022 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
4023 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
4034 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename,
4035 const char *mime_type)
4037 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4040 AVOutputFormat *stream_fmt;
4041 char stream_format_name[64];
4043 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4044 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4053 static void report_config_error(const char *filename, int line_num, int *errors, const char *fmt, ...)
4057 fprintf(stderr, "%s:%d: ", filename, line_num);
4058 vfprintf(stderr, fmt, vl);
4064 static int parse_ffconfig(const char *filename)
4071 int val, errors, line_num;
4072 FFStream **last_stream, *stream, *redirect;
4073 FFStream **last_feed, *feed, *s;
4074 AVCodecContext audio_enc, video_enc;
4075 enum AVCodecID audio_id, video_id;
4078 f = fopen(filename, "r");
4080 ret = AVERROR(errno);
4081 av_log(NULL, AV_LOG_ERROR, "Could not open the configuration file '%s'\n", filename);
4087 first_stream = NULL;
4088 last_stream = &first_stream;
4090 last_feed = &first_feed;
4094 audio_id = AV_CODEC_ID_NONE;
4095 video_id = AV_CODEC_ID_NONE;
4097 #define ERROR(...) report_config_error(filename, line_num, &errors, __VA_ARGS__)
4099 if (fgets(line, sizeof(line), f) == NULL)
4103 while (av_isspace(*p))
4105 if (*p == '\0' || *p == '#')
4108 get_arg(cmd, sizeof(cmd), &p);
4110 if (!av_strcasecmp(cmd, "Port")) {
4111 get_arg(arg, sizeof(arg), &p);
4113 if (val < 1 || val > 65536) {
4114 ERROR("Invalid_port: %s\n", arg);
4116 my_http_addr.sin_port = htons(val);
4117 } else if (!av_strcasecmp(cmd, "BindAddress")) {
4118 get_arg(arg, sizeof(arg), &p);
4119 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4120 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4122 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4123 // do nothing here, its the default now
4124 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4125 get_arg(arg, sizeof(arg), &p);
4127 if (val < 1 || val > 65536) {
4128 ERROR("%s:%d: Invalid port: %s\n", arg);
4130 my_rtsp_addr.sin_port = htons(atoi(arg));
4131 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4132 get_arg(arg, sizeof(arg), &p);
4133 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4134 ERROR("Invalid host/IP address: %s\n", arg);
4136 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4137 get_arg(arg, sizeof(arg), &p);
4139 if (val < 1 || val > 65536) {
4140 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4142 nb_max_http_connections = val;
4143 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4144 get_arg(arg, sizeof(arg), &p);
4146 if (val < 1 || val > nb_max_http_connections) {
4147 ERROR("Invalid MaxClients: %s\n", arg);
4149 nb_max_connections = val;
4151 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4153 get_arg(arg, sizeof(arg), &p);
4154 llval = strtoll(arg, NULL, 10);
4155 if (llval < 10 || llval > 10000000) {
4156 ERROR("Invalid MaxBandwidth: %s\n", arg);
4158 max_bandwidth = llval;
4159 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4160 if (!ffserver_debug)
4161 get_arg(logfilename, sizeof(logfilename), &p);
4162 } else if (!av_strcasecmp(cmd, "<Feed")) {
4163 /*********************************************/
4164 /* Feed related options */
4166 if (stream || feed) {
4167 ERROR("Already in a tag\n");
4169 feed = av_mallocz(sizeof(FFStream));
4171 ret = AVERROR(ENOMEM);
4174 get_arg(feed->filename, sizeof(feed->filename), &p);
4175 q = strrchr(feed->filename, '>');
4179 for (s = first_feed; s; s = s->next) {
4180 if (!strcmp(feed->filename, s->filename)) {
4181 ERROR("Feed '%s' already registered\n", s->filename);
4185 feed->fmt = av_guess_format("ffm", NULL, NULL);
4186 /* default feed file */
4187 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4188 "/tmp/%s.ffm", feed->filename);
4189 feed->feed_max_size = 5 * 1024 * 1024;
4191 feed->feed = feed; /* self feeding :-) */
4193 /* add in stream list */
4194 *last_stream = feed;
4195 last_stream = &feed->next;
4196 /* add in feed list */
4198 last_feed = &feed->next_feed;
4200 } else if (!av_strcasecmp(cmd, "Launch")) {
4204 feed->child_argv = av_mallocz(64 * sizeof(char *));
4205 if (!feed->child_argv) {
4206 ret = AVERROR(ENOMEM);
4209 for (i = 0; i < 62; i++) {
4210 get_arg(arg, sizeof(arg), &p);
4214 feed->child_argv[i] = av_strdup(arg);
4215 if (!feed->child_argv[i]) {
4216 ret = AVERROR(ENOMEM);
4221 feed->child_argv[i] =
4222 av_asprintf("http://%s:%d/%s",
4223 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4224 inet_ntoa(my_http_addr.sin_addr), ntohs(my_http_addr.sin_port),
4226 if (!feed->child_argv[i]) {
4227 ret = AVERROR(ENOMEM);
4231 } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
4233 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4234 feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile");
4235 } else if (stream) {
4236 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4238 } else if (!av_strcasecmp(cmd, "Truncate")) {
4240 get_arg(arg, sizeof(arg), &p);
4241 /* assume Truncate is true in case no argument is specified */
4245 av_log(NULL, AV_LOG_WARNING,
4246 "Truncate N syntax in configuration file is deprecated, "
4247 "use Truncate alone with no arguments\n");
4248 feed->truncate = strtod(arg, NULL);
4251 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4256 get_arg(arg, sizeof(arg), &p);
4258 fsize = strtod(p1, &p1);
4259 switch(av_toupper(*p1)) {
4264 fsize *= 1024 * 1024;
4267 fsize *= 1024 * 1024 * 1024;
4270 feed->feed_max_size = (int64_t)fsize;
4271 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4272 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4275 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4277 ERROR("No corresponding <Feed> for </Feed>\n");
4280 } else if (!av_strcasecmp(cmd, "<Stream")) {
4281 /*********************************************/
4282 /* Stream related options */
4284 if (stream || feed) {
4285 ERROR("Already in a tag\n");
4288 stream = av_mallocz(sizeof(FFStream));
4290 ret = AVERROR(ENOMEM);
4293 get_arg(stream->filename, sizeof(stream->filename), &p);
4294 q = strrchr(stream->filename, '>');
4298 for (s = first_stream; s; s = s->next) {
4299 if (!strcmp(stream->filename, s->filename)) {
4300 ERROR("Stream '%s' already registered\n", s->filename);
4304 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4305 avcodec_get_context_defaults3(&video_enc, NULL);
4306 avcodec_get_context_defaults3(&audio_enc, NULL);
4308 audio_id = AV_CODEC_ID_NONE;
4309 video_id = AV_CODEC_ID_NONE;
4311 audio_id = stream->fmt->audio_codec;
4312 video_id = stream->fmt->video_codec;
4315 *last_stream = stream;
4316 last_stream = &stream->next;
4318 } else if (!av_strcasecmp(cmd, "Feed")) {
4319 get_arg(arg, sizeof(arg), &p);
4324 while (sfeed != NULL) {
4325 if (!strcmp(sfeed->filename, arg))
4327 sfeed = sfeed->next_feed;
4330 ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg, stream->filename);
4332 stream->feed = sfeed;
4334 } else if (!av_strcasecmp(cmd, "Format")) {
4335 get_arg(arg, sizeof(arg), &p);
4337 if (!strcmp(arg, "status")) {
4338 stream->stream_type = STREAM_TYPE_STATUS;
4341 stream->stream_type = STREAM_TYPE_LIVE;
4342 /* jpeg cannot be used here, so use single frame jpeg */
4343 if (!strcmp(arg, "jpeg"))
4344 strcpy(arg, "mjpeg");
4345 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4347 ERROR("Unknown Format: %s\n", arg);
4351 audio_id = stream->fmt->audio_codec;
4352 video_id = stream->fmt->video_codec;
4355 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4356 get_arg(arg, sizeof(arg), &p);
4358 stream->ifmt = av_find_input_format(arg);
4359 if (!stream->ifmt) {
4360 ERROR("Unknown input format: %s\n", arg);
4363 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4364 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4365 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4367 ERROR("FaviconURL only permitted for status streams\n");
4369 } else if (!av_strcasecmp(cmd, "Author")) {
4371 get_arg(stream->author, sizeof(stream->author), &p);
4372 } else if (!av_strcasecmp(cmd, "Comment")) {
4374 get_arg(stream->comment, sizeof(stream->comment), &p);
4375 } else if (!av_strcasecmp(cmd, "Copyright")) {
4377 get_arg(stream->copyright, sizeof(stream->copyright), &p);
4378 } else if (!av_strcasecmp(cmd, "Title")) {
4380 get_arg(stream->title, sizeof(stream->title), &p);
4381 } else if (!av_strcasecmp(cmd, "Preroll")) {
4382 get_arg(arg, sizeof(arg), &p);
4384 stream->prebuffer = atof(arg) * 1000;
4385 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4387 stream->send_on_key = 1;
4388 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4389 get_arg(arg, sizeof(arg), &p);
4390 audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO);
4391 if (audio_id == AV_CODEC_ID_NONE) {
4392 ERROR("Unknown AudioCodec: %s\n", arg);
4394 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4395 get_arg(arg, sizeof(arg), &p);
4396 video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO);
4397 if (video_id == AV_CODEC_ID_NONE) {
4398 ERROR("Unknown VideoCodec: %s\n", arg);
4400 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4401 get_arg(arg, sizeof(arg), &p);
4403 stream->max_time = atof(arg) * 1000;
4404 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4405 get_arg(arg, sizeof(arg), &p);
4407 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4408 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4409 get_arg(arg, sizeof(arg), &p);
4411 audio_enc.channels = atoi(arg);
4412 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4413 get_arg(arg, sizeof(arg), &p);
4415 audio_enc.sample_rate = atoi(arg);
4416 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4418 int minrate, maxrate;
4420 get_arg(arg, sizeof(arg), &p);
4422 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4423 video_enc.rc_min_rate = minrate * 1000;
4424 video_enc.rc_max_rate = maxrate * 1000;
4426 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4429 } else if (!av_strcasecmp(cmd, "Debug")) {
4431 get_arg(arg, sizeof(arg), &p);
4432 video_enc.debug = strtol(arg,0,0);
4434 } else if (!av_strcasecmp(cmd, "Strict")) {
4436 get_arg(arg, sizeof(arg), &p);
4437 video_enc.strict_std_compliance = atoi(arg);
4439 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4441 get_arg(arg, sizeof(arg), &p);
4442 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4444 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4446 get_arg(arg, sizeof(arg), &p);
4447 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4449 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4450 get_arg(arg, sizeof(arg), &p);
4452 video_enc.bit_rate = atoi(arg) * 1000;
4454 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4455 get_arg(arg, sizeof(arg), &p);
4457 ret = av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4459 ERROR("Invalid video size '%s'\n", arg);
4461 if ((video_enc.width % 16) != 0 ||
4462 (video_enc.height % 16) != 0) {
4463 ERROR("Image size must be a multiple of 16\n");
4467 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4468 get_arg(arg, sizeof(arg), &p);
4470 AVRational frame_rate;
4471 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4472 ERROR("Incorrect frame rate: %s\n", arg);
4474 video_enc.time_base.num = frame_rate.den;
4475 video_enc.time_base.den = frame_rate.num;
4478 } else if (!av_strcasecmp(cmd, "PixelFormat")) {
4479 get_arg(arg, sizeof(arg), &p);
4481 video_enc.pix_fmt = av_get_pix_fmt(arg);
4482 if (video_enc.pix_fmt == AV_PIX_FMT_NONE) {
4483 ERROR("Unknown pixel format: %s\n", arg);
4486 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4487 get_arg(arg, sizeof(arg), &p);
4489 video_enc.gop_size = atoi(arg);
4490 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4492 video_enc.gop_size = 1;
4493 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4495 video_enc.mb_decision = FF_MB_DECISION_BITS;
4496 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4498 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4499 video_enc.flags |= CODEC_FLAG_4MV;
4501 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4502 !av_strcasecmp(cmd, "AVOptionAudio")) {
4504 AVCodecContext *avctx;
4506 get_arg(arg, sizeof(arg), &p);
4507 get_arg(arg2, sizeof(arg2), &p);
4508 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4510 type = AV_OPT_FLAG_VIDEO_PARAM;
4513 type = AV_OPT_FLAG_AUDIO_PARAM;
4515 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4516 ERROR("Error setting %s option to %s %s\n", cmd, arg, arg2);
4518 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4519 !av_strcasecmp(cmd, "AVPresetAudio")) {
4520 AVCodecContext *avctx;
4522 get_arg(arg, sizeof(arg), &p);
4523 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4525 video_enc.codec_id = video_id;
4526 type = AV_OPT_FLAG_VIDEO_PARAM;
4529 audio_enc.codec_id = audio_id;
4530 type = AV_OPT_FLAG_AUDIO_PARAM;
4532 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4533 ERROR("AVPreset error: %s\n", arg);
4535 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4536 get_arg(arg, sizeof(arg), &p);
4537 if ((strlen(arg) == 4) && stream)
4538 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4539 } else if (!av_strcasecmp(cmd, "BitExact")) {
4541 video_enc.flags |= CODEC_FLAG_BITEXACT;
4542 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4544 video_enc.dct_algo = FF_DCT_FASTINT;
4545 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4547 video_enc.idct_algo = FF_IDCT_SIMPLE;
4548 } else if (!av_strcasecmp(cmd, "Qscale")) {
4549 get_arg(arg, sizeof(arg), &p);
4551 video_enc.flags |= CODEC_FLAG_QSCALE;
4552 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4554 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4555 get_arg(arg, sizeof(arg), &p);
4557 video_enc.max_qdiff = atoi(arg);
4558 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4559 ERROR("VideoQDiff out of range\n");
4562 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4563 get_arg(arg, sizeof(arg), &p);
4565 video_enc.qmax = atoi(arg);
4566 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4567 ERROR("VideoQMax out of range\n");
4570 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4571 get_arg(arg, sizeof(arg), &p);
4573 video_enc.qmin = atoi(arg);
4574 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4575 ERROR("VideoQMin out of range\n");
4578 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4579 get_arg(arg, sizeof(arg), &p);
4581 video_enc.lumi_masking = atof(arg);
4582 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4583 get_arg(arg, sizeof(arg), &p);
4585 video_enc.dark_masking = atof(arg);
4586 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4587 video_id = AV_CODEC_ID_NONE;
4588 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4589 audio_id = AV_CODEC_ID_NONE;
4590 } else if (!av_strcasecmp(cmd, "ACL")) {
4591 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4592 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4594 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4596 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4597 get_arg(arg, sizeof(arg), &p);
4599 av_freep(&stream->rtsp_option);
4600 stream->rtsp_option = av_strdup(arg);
4602 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4603 get_arg(arg, sizeof(arg), &p);
4605 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4606 ERROR("Invalid host/IP address: %s\n", arg);
4608 stream->is_multicast = 1;
4609 stream->loop = 1; /* default is looping */
4611 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4612 get_arg(arg, sizeof(arg), &p);
4614 stream->multicast_port = atoi(arg);
4615 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4616 get_arg(arg, sizeof(arg), &p);
4618 stream->multicast_ttl = atoi(arg);
4619 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4622 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4624 ERROR("No corresponding <Stream> for </Stream>\n");
4626 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4627 if (audio_id != AV_CODEC_ID_NONE) {
4628 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4629 audio_enc.codec_id = audio_id;
4630 add_codec(stream, &audio_enc);
4632 if (video_id != AV_CODEC_ID_NONE) {
4633 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4634 video_enc.codec_id = video_id;
4635 add_codec(stream, &video_enc);
4640 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4641 /*********************************************/
4643 if (stream || feed || redirect) {
4644 ERROR("Already in a tag\n");
4646 redirect = av_mallocz(sizeof(FFStream));
4648 ret = AVERROR(ENOMEM);
4651 *last_stream = redirect;
4652 last_stream = &redirect->next;
4654 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4655 q = strrchr(redirect->filename, '>');
4658 redirect->stream_type = STREAM_TYPE_REDIRECT;
4660 } else if (!av_strcasecmp(cmd, "URL")) {
4662 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4663 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4665 ERROR("No corresponding <Redirect> for </Redirect>\n");
4667 if (!redirect->feed_filename[0]) {
4668 ERROR("No URL found for <Redirect>\n");
4672 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4673 ERROR("Loadable modules no longer supported\n");
4675 ERROR("Incorrect keyword: '%s'\n", cmd);
4685 return AVERROR(EINVAL);
4690 static void handle_child_exit(int sig)
4695 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4698 for (feed = first_feed; feed; feed = feed->next) {
4699 if (feed->pid == pid) {
4700 int uptime = time(0) - feed->pid_start;
4703 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4706 /* Turn off any more restarts */
4707 feed->child_argv = 0;
4712 need_to_start_children = 1;
4715 static void opt_debug(void)
4718 logfilename[0] = '-';
4721 void show_help_default(const char *opt, const char *arg)
4723 printf("usage: ffserver [options]\n"
4724 "Hyper fast multi format Audio/Video streaming server\n");
4726 show_help_options(options, "Main options:", 0, 0, 0);
4729 static const OptionDef options[] = {
4730 #include "cmdutils_common_opts.h"
4731 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4732 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4733 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4737 int main(int argc, char **argv)
4739 struct sigaction sigact = { { 0 } };
4742 config_filename = av_strdup("/etc/ffserver.conf");
4744 parse_loglevel(argc, argv, options);
4746 avformat_network_init();
4748 show_banner(argc, argv, options);
4750 my_program_name = argv[0];
4752 parse_options(NULL, argc, argv, options, NULL);
4754 unsetenv("http_proxy"); /* Kill the http_proxy */
4756 av_lfg_init(&random_state, av_get_random_seed());
4758 sigact.sa_handler = handle_child_exit;
4759 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4760 sigaction(SIGCHLD, &sigact, 0);
4762 if ((ret = parse_ffconfig(config_filename)) < 0) {
4763 fprintf(stderr, "Error reading configuration file '%s': %s\n",
4764 config_filename, av_err2str(ret));
4767 av_freep(&config_filename);
4769 /* open log file if needed */
4770 if (logfilename[0] != '\0') {
4771 if (!strcmp(logfilename, "-"))
4774 logfile = fopen(logfilename, "a");
4775 av_log_set_callback(http_av_log);
4778 build_file_streams();
4780 build_feed_streams();
4782 compute_bandwidth();
4785 signal(SIGPIPE, SIG_IGN);
4787 if (http_server() < 0) {
4788 http_log("Could not start server\n");