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/rtspcodes.h"
42 #include "libavformat/avio_internal.h"
43 #include "libavformat/internal.h"
44 #include "libavformat/url.h"
46 #include "libavutil/avassert.h"
47 #include "libavutil/avstring.h"
48 #include "libavutil/lfg.h"
49 #include "libavutil/dict.h"
50 #include "libavutil/intreadwrite.h"
51 #include "libavutil/mathematics.h"
52 #include "libavutil/pixdesc.h"
53 #include "libavutil/random_seed.h"
54 #include "libavutil/parseutils.h"
55 #include "libavutil/opt.h"
56 #include "libavutil/time.h"
63 #include <sys/ioctl.h>
74 const char program_name[] = "ffserver";
75 const int program_birth_year = 2000;
77 static const OptionDef options[];
80 HTTPSTATE_WAIT_REQUEST,
81 HTTPSTATE_SEND_HEADER,
82 HTTPSTATE_SEND_DATA_HEADER,
83 HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */
84 HTTPSTATE_SEND_DATA_TRAILER,
85 HTTPSTATE_RECEIVE_DATA,
86 HTTPSTATE_WAIT_FEED, /* wait for data from the feed */
89 RTSPSTATE_WAIT_REQUEST,
91 RTSPSTATE_SEND_PACKET,
94 static const char * const http_state[] = {
110 #define MAX_STREAMS 20
112 #define IOBUFFER_INIT_SIZE 8192
114 /* timeouts are in ms */
115 #define HTTP_REQUEST_TIMEOUT (15 * 1000)
116 #define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000)
118 #define SYNC_TIMEOUT (10 * 1000)
120 typedef struct RTSPActionServerSetup {
122 char transport_option[512];
123 } RTSPActionServerSetup;
126 int64_t count1, count2;
127 int64_t time1, time2;
130 /* context associated with one connection */
131 typedef struct HTTPContext {
132 enum HTTPState state;
133 int fd; /* socket file descriptor */
134 struct sockaddr_in from_addr; /* origin */
135 struct pollfd *poll_entry; /* used when polling */
137 uint8_t *buffer_ptr, *buffer_end;
140 int chunked_encoding;
141 int chunk_size; /* 0 if it needs to be read */
142 struct HTTPContext *next;
143 int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */
147 /* input format handling */
148 AVFormatContext *fmt_in;
149 int64_t start_time; /* In milliseconds - this wraps fairly often */
150 int64_t first_pts; /* initial pts value */
151 int64_t cur_pts; /* current pts value from the stream in us */
152 int64_t cur_frame_duration; /* duration of the current frame in us */
153 int cur_frame_bytes; /* output frame size, needed to compute
154 the time at which we send each
156 int pts_stream_index; /* stream we choose as clock reference */
157 int64_t cur_clock; /* current clock reference value in us */
158 /* output format handling */
159 struct FFStream *stream;
160 /* -1 is invalid stream */
161 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
162 int switch_feed_streams[MAX_STREAMS]; /* index of streams in the feed */
164 AVFormatContext fmt_ctx; /* instance of FFStream for one user */
165 int last_packet_sent; /* true if last data packet was sent */
167 DataRateData datarate;
174 int is_packetized; /* if true, the stream is packetized */
175 int packet_stream_index; /* current stream for output in state machine */
177 /* RTSP state specific */
178 uint8_t *pb_buffer; /* XXX: use that in all the code */
180 int seq; /* RTSP sequence number */
182 /* RTP state specific */
183 enum RTSPLowerTransport rtp_protocol;
184 char session_id[32]; /* session id */
185 AVFormatContext *rtp_ctx[MAX_STREAMS];
187 /* RTP/UDP specific */
188 URLContext *rtp_handles[MAX_STREAMS];
190 /* RTP/TCP specific */
191 struct HTTPContext *rtsp_c;
192 uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end;
195 /* each generated stream is described here */
199 STREAM_TYPE_REDIRECT,
202 enum IPAddressAction {
207 typedef struct IPAddressACL {
208 struct IPAddressACL *next;
209 enum IPAddressAction action;
210 /* These are in host order */
211 struct in_addr first;
215 /* description of each stream of the ffserver.conf file */
216 typedef struct FFStream {
217 enum StreamType stream_type;
218 char filename[1024]; /* stream filename */
219 struct FFStream *feed; /* feed we are using (can be null if
221 AVDictionary *in_opts; /* input parameters */
222 AVDictionary *metadata; /* metadata to set on the stream */
223 AVInputFormat *ifmt; /* if non NULL, force input format */
226 char dynamic_acl[1024];
228 int prebuffer; /* Number of milliseconds early to start */
229 int64_t max_time; /* Number of milliseconds to run */
231 AVStream *streams[MAX_STREAMS];
232 int feed_streams[MAX_STREAMS]; /* index of streams in the feed */
233 char feed_filename[1024]; /* file name of the feed storage, or
234 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_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only);
296 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
297 struct in_addr my_ip);
300 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
301 FFStream *stream, const char *session_id,
302 enum RTSPLowerTransport rtp_protocol);
303 static int rtp_new_av_stream(HTTPContext *c,
304 int stream_index, struct sockaddr_in *dest_addr,
305 HTTPContext *rtsp_c);
307 static const char *my_program_name;
309 static const char *config_filename;
311 static int ffserver_debug;
312 static int no_launch;
313 static int need_to_start_children;
315 /* maximum number of simultaneous HTTP connections */
316 static unsigned int nb_max_http_connections = 2000;
317 static unsigned int nb_max_connections = 5;
318 static unsigned int nb_connections;
320 static uint64_t max_bandwidth = 1000;
321 static uint64_t current_bandwidth;
323 static int64_t cur_time; // Making this global saves on passing it around everywhere
325 static AVLFG random_state;
327 static FILE *logfile = NULL;
329 static void htmlstrip(char *s) {
331 s += strspn(s, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,. ");
337 static int64_t ffm_read_write_index(int fd)
341 if (lseek(fd, 8, SEEK_SET) < 0)
343 if (read(fd, buf, 8) != 8)
348 static int ffm_write_write_index(int fd, int64_t pos)
354 buf[i] = (pos >> (56 - i * 8)) & 0xff;
355 if (lseek(fd, 8, SEEK_SET) < 0)
357 if (write(fd, buf, 8) != 8)
362 static void ffm_set_write_index(AVFormatContext *s, int64_t pos,
365 FFMContext *ffm = s->priv_data;
366 ffm->write_index = pos;
367 ffm->file_size = file_size;
370 /* FIXME: make ffserver work with IPv6 */
371 /* resolve host with also IP address parsing */
372 static int resolve_host(struct in_addr *sin_addr, const char *hostname)
375 if (!ff_inet_aton(hostname, sin_addr)) {
377 struct addrinfo *ai, *cur;
378 struct addrinfo hints = { 0 };
379 hints.ai_family = AF_INET;
380 if (getaddrinfo(hostname, NULL, &hints, &ai))
382 /* getaddrinfo returns a linked list of addrinfo structs.
383 * Even if we set ai_family = AF_INET above, make sure
384 * that the returned one actually is of the correct type. */
385 for (cur = ai; cur; cur = cur->ai_next) {
386 if (cur->ai_family == AF_INET) {
387 *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr;
396 hp = gethostbyname(hostname);
399 memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
405 static char *ctime1(char *buf2, int buf_size)
412 av_strlcpy(buf2, p, buf_size);
413 p = buf2 + strlen(p) - 1;
419 static void http_vlog(const char *fmt, va_list vargs)
421 static int print_prefix = 1;
425 ctime1(buf, sizeof(buf));
426 fprintf(logfile, "%s ", buf);
428 print_prefix = strstr(fmt, "\n") != NULL;
429 vfprintf(logfile, fmt, vargs);
435 __attribute__ ((format (printf, 1, 2)))
437 static void http_log(const char *fmt, ...)
440 va_start(vargs, fmt);
441 http_vlog(fmt, vargs);
445 static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
447 static int print_prefix = 1;
448 AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
449 if (level > av_log_get_level())
451 if (print_prefix && avc)
452 http_log("[%s @ %p]", avc->item_name(ptr), ptr);
453 print_prefix = strstr(fmt, "\n") != NULL;
454 http_vlog(fmt, vargs);
457 static void log_connection(HTTPContext *c)
462 http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n",
463 inet_ntoa(c->from_addr.sin_addr), c->method, c->url,
464 c->protocol, (c->http_error ? c->http_error : 200), c->data_count);
467 static void update_datarate(DataRateData *drd, int64_t count)
469 if (!drd->time1 && !drd->count1) {
470 drd->time1 = drd->time2 = cur_time;
471 drd->count1 = drd->count2 = count;
472 } else if (cur_time - drd->time2 > 5000) {
473 drd->time1 = drd->time2;
474 drd->count1 = drd->count2;
475 drd->time2 = cur_time;
480 /* In bytes per second */
481 static int compute_datarate(DataRateData *drd, int64_t count)
483 if (cur_time == drd->time1)
486 return ((count - drd->count1) * 1000) / (cur_time - drd->time1);
490 static void start_children(FFStream *feed)
495 for (; feed; feed = feed->next) {
496 if (feed->child_argv && !feed->pid) {
497 feed->pid_start = time(0);
502 http_log("Unable to create children\n");
511 /* replace "ffserver" with "ffmpeg" in the path of current
512 * program. Ignore user provided path */
513 av_strlcpy(pathname, my_program_name, sizeof(pathname));
514 slash = strrchr(pathname, '/');
519 strcpy(slash, "ffmpeg");
521 http_log("Launch command line: ");
522 http_log("%s ", pathname);
523 for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++)
524 http_log("%s ", feed->child_argv[i]);
527 for (i = 3; i < 256; i++)
530 if (!ffserver_debug) {
531 if (!freopen("/dev/null", "r", stdin))
532 http_log("failed to redirect STDIN to /dev/null\n;");
533 if (!freopen("/dev/null", "w", stdout))
534 http_log("failed to redirect STDOUT to /dev/null\n;");
535 if (!freopen("/dev/null", "w", stderr))
536 http_log("failed to redirect STDERR to /dev/null\n;");
539 signal(SIGPIPE, SIG_DFL);
541 execvp(pathname, feed->child_argv);
549 /* open a listening socket */
550 static int socket_open_listen(struct sockaddr_in *my_addr)
554 server_fd = socket(AF_INET,SOCK_STREAM,0);
561 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)))
562 av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n");
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);
579 if (ff_socket_nonblock(server_fd, 1) < 0)
580 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
585 /* start all multicast streams */
586 static void start_multicast(void)
591 struct sockaddr_in dest_addr = {0};
592 int default_port, stream_index;
595 for(stream = first_stream; stream; stream = stream->next) {
596 if (stream->is_multicast) {
597 unsigned random0 = av_lfg_get(&random_state);
598 unsigned random1 = av_lfg_get(&random_state);
599 /* open the RTP connection */
600 snprintf(session_id, sizeof(session_id), "%08x%08x",
603 /* choose a port if none given */
604 if (stream->multicast_port == 0) {
605 stream->multicast_port = default_port;
609 dest_addr.sin_family = AF_INET;
610 dest_addr.sin_addr = stream->multicast_ip;
611 dest_addr.sin_port = htons(stream->multicast_port);
613 rtp_c = rtp_new_connection(&dest_addr, stream, session_id,
614 RTSP_LOWER_TRANSPORT_UDP_MULTICAST);
618 if (open_input_stream(rtp_c, "") < 0) {
619 http_log("Could not open input stream for stream '%s'\n",
624 /* open each RTP stream */
625 for(stream_index = 0; stream_index < stream->nb_streams;
627 dest_addr.sin_port = htons(stream->multicast_port +
629 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) < 0) {
630 http_log("Could not open output stream '%s/streamid=%d'\n",
631 stream->filename, stream_index);
636 rtp_c->state = HTTPSTATE_SEND_DATA;
641 /* main loop of the HTTP server */
642 static int http_server(void)
644 int server_fd = 0, rtsp_server_fd = 0;
646 struct pollfd *poll_table, *poll_entry;
647 HTTPContext *c, *c_next;
649 if(!(poll_table = av_mallocz_array(nb_max_http_connections + 2, sizeof(*poll_table)))) {
650 http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
654 if (my_http_addr.sin_port) {
655 server_fd = socket_open_listen(&my_http_addr);
662 if (my_rtsp_addr.sin_port) {
663 rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
664 if (rtsp_server_fd < 0) {
666 closesocket(server_fd);
671 if (!rtsp_server_fd && !server_fd) {
672 http_log("HTTP and RTSP disabled.\n");
677 http_log("FFserver started.\n");
679 start_children(first_feed);
684 poll_entry = poll_table;
686 poll_entry->fd = server_fd;
687 poll_entry->events = POLLIN;
690 if (rtsp_server_fd) {
691 poll_entry->fd = rtsp_server_fd;
692 poll_entry->events = POLLIN;
696 /* wait for events on each HTTP handle */
703 case HTTPSTATE_SEND_HEADER:
704 case RTSPSTATE_SEND_REPLY:
705 case RTSPSTATE_SEND_PACKET:
706 c->poll_entry = poll_entry;
708 poll_entry->events = POLLOUT;
711 case HTTPSTATE_SEND_DATA_HEADER:
712 case HTTPSTATE_SEND_DATA:
713 case HTTPSTATE_SEND_DATA_TRAILER:
714 if (!c->is_packetized) {
715 /* for TCP, we output as much as we can
716 * (may need to put a limit) */
717 c->poll_entry = poll_entry;
719 poll_entry->events = POLLOUT;
722 /* when ffserver is doing the timing, we work by
723 looking at which packet needs to be sent every
725 /* one tick wait XXX: 10 ms assumed */
730 case HTTPSTATE_WAIT_REQUEST:
731 case HTTPSTATE_RECEIVE_DATA:
732 case HTTPSTATE_WAIT_FEED:
733 case RTSPSTATE_WAIT_REQUEST:
734 /* need to catch errors */
735 c->poll_entry = poll_entry;
737 poll_entry->events = POLLIN;/* Maybe this will work */
741 c->poll_entry = NULL;
747 /* wait for an event on one connection. We poll at least every
748 second to handle timeouts */
750 ret = poll(poll_table, poll_entry - poll_table, delay);
751 if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
752 ff_neterrno() != AVERROR(EINTR)) {
758 cur_time = av_gettime() / 1000;
760 if (need_to_start_children) {
761 need_to_start_children = 0;
762 start_children(first_feed);
765 /* now handle the events */
766 for(c = first_http_ctx; c; c = c_next) {
768 if (handle_connection(c) < 0) {
770 /* close and free the connection */
775 poll_entry = poll_table;
777 /* new HTTP connection request ? */
778 if (poll_entry->revents & POLLIN)
779 new_connection(server_fd, 0);
782 if (rtsp_server_fd) {
783 /* new RTSP connection request ? */
784 if (poll_entry->revents & POLLIN)
785 new_connection(rtsp_server_fd, 1);
790 /* start waiting for a new HTTP/RTSP request */
791 static void start_wait_request(HTTPContext *c, int is_rtsp)
793 c->buffer_ptr = c->buffer;
794 c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
797 c->timeout = cur_time + RTSP_REQUEST_TIMEOUT;
798 c->state = RTSPSTATE_WAIT_REQUEST;
800 c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
801 c->state = HTTPSTATE_WAIT_REQUEST;
805 static void http_send_too_busy_reply(int fd)
808 int len = snprintf(buffer, sizeof(buffer),
809 "HTTP/1.0 503 Server too busy\r\n"
810 "Content-type: text/html\r\n"
812 "<html><head><title>Too busy</title></head><body>\r\n"
813 "<p>The server is too busy to serve your request at this time.</p>\r\n"
814 "<p>The number of current connections is %u, and this exceeds the limit of %u.</p>\r\n"
815 "</body></html>\r\n",
816 nb_connections, nb_max_connections);
817 av_assert0(len < sizeof(buffer));
818 if (send(fd, buffer, len, 0) < len)
819 av_log(NULL, AV_LOG_WARNING, "Could not send too-busy reply, send() failed\n");
823 static void new_connection(int server_fd, int is_rtsp)
825 struct sockaddr_in from_addr;
828 HTTPContext *c = NULL;
830 len = sizeof(from_addr);
831 fd = accept(server_fd, (struct sockaddr *)&from_addr,
834 http_log("error during accept %s\n", strerror(errno));
837 if (ff_socket_nonblock(fd, 1) < 0)
838 av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
840 if (nb_connections >= nb_max_connections) {
841 http_send_too_busy_reply(fd);
845 /* add a new connection */
846 c = av_mallocz(sizeof(HTTPContext));
851 c->poll_entry = NULL;
852 c->from_addr = from_addr;
853 c->buffer_size = IOBUFFER_INIT_SIZE;
854 c->buffer = av_malloc(c->buffer_size);
858 c->next = first_http_ctx;
862 start_wait_request(c, is_rtsp);
868 av_freep(&c->buffer);
874 static void close_connection(HTTPContext *c)
876 HTTPContext **cp, *c1;
878 AVFormatContext *ctx;
882 /* remove connection from list */
883 cp = &first_http_ctx;
892 /* remove references, if any (XXX: do it faster) */
893 for(c1 = first_http_ctx; c1; c1 = c1->next) {
898 /* remove connection associated resources */
902 /* close each frame parser */
903 for(i=0;i<c->fmt_in->nb_streams;i++) {
904 st = c->fmt_in->streams[i];
905 if (st->codec->codec)
906 avcodec_close(st->codec);
908 avformat_close_input(&c->fmt_in);
911 /* free RTP output streams if any */
914 nb_streams = c->stream->nb_streams;
916 for(i=0;i<nb_streams;i++) {
919 av_write_trailer(ctx);
920 av_dict_free(&ctx->metadata);
921 av_freep(&ctx->streams[0]);
924 h = c->rtp_handles[i];
931 if (!c->last_packet_sent && c->state == HTTPSTATE_SEND_DATA_TRAILER) {
934 if (avio_open_dyn_buf(&ctx->pb) >= 0) {
935 av_write_trailer(ctx);
936 av_freep(&c->pb_buffer);
937 avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
942 for(i=0; i<ctx->nb_streams; i++)
943 av_freep(&ctx->streams[i]);
944 av_freep(&ctx->streams);
945 av_freep(&ctx->priv_data);
947 if (c->stream && !c->post && c->stream->stream_type == STREAM_TYPE_LIVE)
948 current_bandwidth -= c->stream->bandwidth;
950 /* signal that there is no feed if we are the feeder socket */
951 if (c->state == HTTPSTATE_RECEIVE_DATA && c->stream) {
952 c->stream->feed_opened = 0;
956 av_freep(&c->pb_buffer);
957 av_freep(&c->packet_buffer);
958 av_freep(&c->buffer);
963 static int handle_connection(HTTPContext *c)
968 case HTTPSTATE_WAIT_REQUEST:
969 case RTSPSTATE_WAIT_REQUEST:
971 if ((c->timeout - cur_time) < 0)
973 if (c->poll_entry->revents & (POLLERR | POLLHUP))
976 /* no need to read if no events */
977 if (!(c->poll_entry->revents & POLLIN))
981 len = recv(c->fd, c->buffer_ptr, 1, 0);
983 if (ff_neterrno() != AVERROR(EAGAIN) &&
984 ff_neterrno() != AVERROR(EINTR))
986 } else if (len == 0) {
989 /* search for end of request. */
991 c->buffer_ptr += len;
993 if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
994 (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
995 /* request found : parse it and reply */
996 if (c->state == HTTPSTATE_WAIT_REQUEST) {
997 ret = http_parse_request(c);
999 ret = rtsp_parse_request(c);
1003 } else if (ptr >= c->buffer_end) {
1004 /* request too long: cannot do anything */
1006 } else goto read_loop;
1010 case HTTPSTATE_SEND_HEADER:
1011 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1014 /* no need to write if no events */
1015 if (!(c->poll_entry->revents & POLLOUT))
1017 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1019 if (ff_neterrno() != AVERROR(EAGAIN) &&
1020 ff_neterrno() != AVERROR(EINTR)) {
1021 goto close_connection;
1024 c->buffer_ptr += len;
1026 c->stream->bytes_served += len;
1027 c->data_count += len;
1028 if (c->buffer_ptr >= c->buffer_end) {
1029 av_freep(&c->pb_buffer);
1030 /* if error, exit */
1033 /* all the buffer was sent : synchronize to the incoming
1035 c->state = HTTPSTATE_SEND_DATA_HEADER;
1036 c->buffer_ptr = c->buffer_end = c->buffer;
1041 case HTTPSTATE_SEND_DATA:
1042 case HTTPSTATE_SEND_DATA_HEADER:
1043 case HTTPSTATE_SEND_DATA_TRAILER:
1044 /* for packetized output, we consider we can always write (the
1045 input streams set the speed). It may be better to verify
1046 that we do not rely too much on the kernel queues */
1047 if (!c->is_packetized) {
1048 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1051 /* no need to read if no events */
1052 if (!(c->poll_entry->revents & POLLOUT))
1055 if (http_send_data(c) < 0)
1057 /* close connection if trailer sent */
1058 if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
1061 case HTTPSTATE_RECEIVE_DATA:
1062 /* no need to read if no events */
1063 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1065 if (!(c->poll_entry->revents & POLLIN))
1067 if (http_receive_data(c) < 0)
1070 case HTTPSTATE_WAIT_FEED:
1071 /* no need to read if no events */
1072 if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP))
1075 /* nothing to do, we'll be waken up by incoming feed packets */
1078 case RTSPSTATE_SEND_REPLY:
1079 if (c->poll_entry->revents & (POLLERR | POLLHUP))
1080 goto close_connection;
1081 /* no need to write if no events */
1082 if (!(c->poll_entry->revents & POLLOUT))
1084 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
1086 if (ff_neterrno() != AVERROR(EAGAIN) &&
1087 ff_neterrno() != AVERROR(EINTR)) {
1088 goto close_connection;
1091 c->buffer_ptr += len;
1092 c->data_count += len;
1093 if (c->buffer_ptr >= c->buffer_end) {
1094 /* all the buffer was sent : wait for a new request */
1095 av_freep(&c->pb_buffer);
1096 start_wait_request(c, 1);
1100 case RTSPSTATE_SEND_PACKET:
1101 if (c->poll_entry->revents & (POLLERR | POLLHUP)) {
1102 av_freep(&c->packet_buffer);
1105 /* no need to write if no events */
1106 if (!(c->poll_entry->revents & POLLOUT))
1108 len = send(c->fd, c->packet_buffer_ptr,
1109 c->packet_buffer_end - c->packet_buffer_ptr, 0);
1111 if (ff_neterrno() != AVERROR(EAGAIN) &&
1112 ff_neterrno() != AVERROR(EINTR)) {
1113 /* error : close connection */
1114 av_freep(&c->packet_buffer);
1118 c->packet_buffer_ptr += len;
1119 if (c->packet_buffer_ptr >= c->packet_buffer_end) {
1120 /* all the buffer was sent : wait for a new request */
1121 av_freep(&c->packet_buffer);
1122 c->state = RTSPSTATE_WAIT_REQUEST;
1126 case HTTPSTATE_READY:
1135 av_freep(&c->pb_buffer);
1139 static int extract_rates(char *rates, int ratelen, const char *request)
1143 for (p = request; *p && *p != '\r' && *p != '\n'; ) {
1144 if (av_strncasecmp(p, "Pragma:", 7) == 0) {
1145 const char *q = p + 7;
1147 while (*q && *q != '\n' && av_isspace(*q))
1150 if (av_strncasecmp(q, "stream-switch-entry=", 20) == 0) {
1156 memset(rates, 0xff, ratelen);
1159 while (*q && *q != '\n' && *q != ':')
1162 if (sscanf(q, ":%d:%d", &stream_no, &rate_no) != 2)
1166 if (stream_no < ratelen && stream_no >= 0)
1167 rates[stream_no] = rate_no;
1169 while (*q && *q != '\n' && !av_isspace(*q))
1176 p = strchr(p, '\n');
1186 static int find_stream_in_feed(FFStream *feed, AVCodecContext *codec, int bit_rate)
1189 int best_bitrate = 100000000;
1192 for (i = 0; i < feed->nb_streams; i++) {
1193 AVCodecContext *feed_codec = feed->streams[i]->codec;
1195 if (feed_codec->codec_id != codec->codec_id ||
1196 feed_codec->sample_rate != codec->sample_rate ||
1197 feed_codec->width != codec->width ||
1198 feed_codec->height != codec->height)
1201 /* Potential stream */
1203 /* We want the fastest stream less than bit_rate, or the slowest
1204 * faster than bit_rate
1207 if (feed_codec->bit_rate <= bit_rate) {
1208 if (best_bitrate > bit_rate || feed_codec->bit_rate > best_bitrate) {
1209 best_bitrate = feed_codec->bit_rate;
1213 if (feed_codec->bit_rate < best_bitrate) {
1214 best_bitrate = feed_codec->bit_rate;
1223 static int modify_current_stream(HTTPContext *c, char *rates)
1226 FFStream *req = c->stream;
1227 int action_required = 0;
1229 /* Not much we can do for a feed */
1233 for (i = 0; i < req->nb_streams; i++) {
1234 AVCodecContext *codec = req->streams[i]->codec;
1238 c->switch_feed_streams[i] = req->feed_streams[i];
1241 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 2);
1244 /* Wants off or slow */
1245 c->switch_feed_streams[i] = find_stream_in_feed(req->feed, codec, codec->bit_rate / 4);
1247 /* This doesn't work well when it turns off the only stream! */
1248 c->switch_feed_streams[i] = -2;
1249 c->feed_streams[i] = -2;
1254 if (c->switch_feed_streams[i] >= 0 && c->switch_feed_streams[i] != c->feed_streams[i])
1255 action_required = 1;
1258 return action_required;
1261 static void get_word(char *buf, int buf_size, const char **pp)
1267 p += strspn(p, SPACE_CHARS);
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;
1378 static IPAddressACL* parse_dynamic_acl(FFStream *stream, HTTPContext *c)
1383 IPAddressACL *acl = NULL;
1387 f = fopen(stream->dynamic_acl, "r");
1389 perror(stream->dynamic_acl);
1393 acl = av_mallocz(sizeof(IPAddressACL));
1397 if (fgets(line, sizeof(line), f) == NULL)
1401 while (av_isspace(*p))
1403 if (*p == '\0' || *p == '#')
1405 get_arg(cmd, sizeof(cmd), &p);
1407 if (!av_strcasecmp(cmd, "ACL"))
1408 parse_acl_row(NULL, NULL, acl, p, stream->dynamic_acl, line_num);
1415 static void free_acl_list(IPAddressACL *in_acl)
1417 IPAddressACL *pacl,*pacl2;
1427 static int validate_acl_list(IPAddressACL *in_acl, HTTPContext *c)
1429 enum IPAddressAction last_action = IP_DENY;
1431 struct in_addr *src = &c->from_addr.sin_addr;
1432 unsigned long src_addr = src->s_addr;
1434 for (acl = in_acl; acl; acl = acl->next) {
1435 if (src_addr >= acl->first.s_addr && src_addr <= acl->last.s_addr)
1436 return (acl->action == IP_ALLOW) ? 1 : 0;
1437 last_action = acl->action;
1440 /* Nothing matched, so return not the last action */
1441 return (last_action == IP_DENY) ? 1 : 0;
1444 static int validate_acl(FFStream *stream, HTTPContext *c)
1450 /* if stream->acl is null validate_acl_list will return 1 */
1451 ret = validate_acl_list(stream->acl, c);
1453 if (stream->dynamic_acl[0]) {
1454 acl = parse_dynamic_acl(stream, c);
1456 ret = validate_acl_list(acl, c);
1464 /* compute the real filename of a file by matching it without its
1465 extensions to all the stream's filenames */
1466 static void compute_real_filename(char *filename, int max_size)
1473 /* compute filename by matching without the file extensions */
1474 av_strlcpy(file1, filename, sizeof(file1));
1475 p = strrchr(file1, '.');
1478 for(stream = first_stream; stream; stream = stream->next) {
1479 av_strlcpy(file2, stream->filename, sizeof(file2));
1480 p = strrchr(file2, '.');
1483 if (!strcmp(file1, file2)) {
1484 av_strlcpy(filename, stream->filename, max_size);
1499 /* parse HTTP request and prepare header */
1500 static int http_parse_request(HTTPContext *c)
1504 enum RedirType redir_type;
1506 char info[1024], filename[1024];
1510 const char *mime_type;
1514 const char *useragent = 0;
1517 get_word(cmd, sizeof(cmd), &p);
1518 av_strlcpy(c->method, cmd, sizeof(c->method));
1520 if (!strcmp(cmd, "GET"))
1522 else if (!strcmp(cmd, "POST"))
1527 get_word(url, sizeof(url), &p);
1528 av_strlcpy(c->url, url, sizeof(c->url));
1530 get_word(protocol, sizeof(protocol), (const char **)&p);
1531 if (strcmp(protocol, "HTTP/1.0") && strcmp(protocol, "HTTP/1.1"))
1534 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
1537 http_log("%s - - New connection: %s %s\n", inet_ntoa(c->from_addr.sin_addr), cmd, url);
1539 /* find the filename and the optional info string in the request */
1540 p1 = strchr(url, '?');
1542 av_strlcpy(info, p1, sizeof(info));
1547 av_strlcpy(filename, url + ((*url == '/') ? 1 : 0), sizeof(filename)-1);
1549 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1550 if (av_strncasecmp(p, "User-Agent:", 11) == 0) {
1552 if (*useragent && *useragent != '\n' && av_isspace(*useragent))
1556 p = strchr(p, '\n');
1563 redir_type = REDIR_NONE;
1564 if (av_match_ext(filename, "asx")) {
1565 redir_type = REDIR_ASX;
1566 filename[strlen(filename)-1] = 'f';
1567 } else if (av_match_ext(filename, "asf") &&
1568 (!useragent || av_strncasecmp(useragent, "NSPlayer", 8) != 0)) {
1569 /* if this isn't WMP or lookalike, return the redirector file */
1570 redir_type = REDIR_ASF;
1571 } else if (av_match_ext(filename, "rpm,ram")) {
1572 redir_type = REDIR_RAM;
1573 strcpy(filename + strlen(filename)-2, "m");
1574 } else if (av_match_ext(filename, "rtsp")) {
1575 redir_type = REDIR_RTSP;
1576 compute_real_filename(filename, sizeof(filename) - 1);
1577 } else if (av_match_ext(filename, "sdp")) {
1578 redir_type = REDIR_SDP;
1579 compute_real_filename(filename, sizeof(filename) - 1);
1582 // "redirect" / request to index.html
1583 if (!strlen(filename))
1584 av_strlcpy(filename, "index.html", sizeof(filename) - 1);
1586 stream = first_stream;
1588 if (!strcmp(stream->filename, filename) && validate_acl(stream, c))
1590 stream = stream->next;
1593 snprintf(msg, sizeof(msg), "File '%s' not found", url);
1594 http_log("File '%s' not found\n", url);
1599 memcpy(c->feed_streams, stream->feed_streams, sizeof(c->feed_streams));
1600 memset(c->switch_feed_streams, -1, sizeof(c->switch_feed_streams));
1602 if (stream->stream_type == STREAM_TYPE_REDIRECT) {
1603 c->http_error = 301;
1605 snprintf(q, c->buffer_size,
1606 "HTTP/1.0 301 Moved\r\n"
1608 "Content-type: text/html\r\n"
1610 "<html><head><title>Moved</title></head><body>\r\n"
1611 "You should be <a href=\"%s\">redirected</a>.\r\n"
1612 "</body></html>\r\n", stream->feed_filename, stream->feed_filename);
1614 /* prepare output buffer */
1615 c->buffer_ptr = c->buffer;
1617 c->state = HTTPSTATE_SEND_HEADER;
1621 /* If this is WMP, get the rate information */
1622 if (extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1623 if (modify_current_stream(c, ratebuf)) {
1624 for (i = 0; i < FF_ARRAY_ELEMS(c->feed_streams); i++) {
1625 if (c->switch_feed_streams[i] >= 0)
1626 c->switch_feed_streams[i] = -1;
1631 if (c->post == 0 && stream->stream_type == STREAM_TYPE_LIVE)
1632 current_bandwidth += stream->bandwidth;
1634 /* If already streaming this feed, do not let start another feeder. */
1635 if (stream->feed_opened) {
1636 snprintf(msg, sizeof(msg), "This feed is already being received.");
1637 http_log("Feed '%s' already being received\n", stream->feed_filename);
1641 if (c->post == 0 && max_bandwidth < current_bandwidth) {
1642 c->http_error = 503;
1644 snprintf(q, c->buffer_size,
1645 "HTTP/1.0 503 Server too busy\r\n"
1646 "Content-type: text/html\r\n"
1648 "<html><head><title>Too busy</title></head><body>\r\n"
1649 "<p>The server is too busy to serve your request at this time.</p>\r\n"
1650 "<p>The bandwidth being served (including your stream) is %"PRIu64"kbit/sec, "
1651 "and this exceeds the limit of %"PRIu64"kbit/sec.</p>\r\n"
1652 "</body></html>\r\n", current_bandwidth, max_bandwidth);
1654 /* prepare output buffer */
1655 c->buffer_ptr = c->buffer;
1657 c->state = HTTPSTATE_SEND_HEADER;
1661 if (redir_type != REDIR_NONE) {
1662 const char *hostinfo = 0;
1664 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1665 if (av_strncasecmp(p, "Host:", 5) == 0) {
1669 p = strchr(p, '\n');
1680 while (av_isspace(*hostinfo))
1683 eoh = strchr(hostinfo, '\n');
1685 if (eoh[-1] == '\r')
1688 if (eoh - hostinfo < sizeof(hostbuf) - 1) {
1689 memcpy(hostbuf, hostinfo, eoh - hostinfo);
1690 hostbuf[eoh - hostinfo] = 0;
1692 c->http_error = 200;
1694 switch(redir_type) {
1696 snprintf(q, c->buffer_size,
1697 "HTTP/1.0 200 ASX Follows\r\n"
1698 "Content-type: video/x-ms-asf\r\n"
1700 "<ASX Version=\"3\">\r\n"
1701 //"<!-- Autogenerated by ffserver -->\r\n"
1702 "<ENTRY><REF HREF=\"http://%s/%s%s\"/></ENTRY>\r\n"
1703 "</ASX>\r\n", hostbuf, filename, info);
1707 snprintf(q, c->buffer_size,
1708 "HTTP/1.0 200 RAM Follows\r\n"
1709 "Content-type: audio/x-pn-realaudio\r\n"
1711 "# Autogenerated by ffserver\r\n"
1712 "http://%s/%s%s\r\n", hostbuf, filename, info);
1716 snprintf(q, c->buffer_size,
1717 "HTTP/1.0 200 ASF Redirect follows\r\n"
1718 "Content-type: video/x-ms-asf\r\n"
1721 "Ref1=http://%s/%s%s\r\n", hostbuf, filename, info);
1726 char hostname[256], *p;
1727 /* extract only hostname */
1728 av_strlcpy(hostname, hostbuf, sizeof(hostname));
1729 p = strrchr(hostname, ':');
1732 snprintf(q, c->buffer_size,
1733 "HTTP/1.0 200 RTSP Redirect follows\r\n"
1734 /* XXX: incorrect MIME type ? */
1735 "Content-type: application/x-rtsp\r\n"
1737 "rtsp://%s:%d/%s\r\n", hostname, ntohs(my_rtsp_addr.sin_port), filename);
1746 struct sockaddr_in my_addr;
1748 snprintf(q, c->buffer_size,
1749 "HTTP/1.0 200 OK\r\n"
1750 "Content-type: application/sdp\r\n"
1754 len = sizeof(my_addr);
1756 /* XXX: Should probably fail? */
1757 if (getsockname(c->fd, (struct sockaddr *)&my_addr, &len))
1758 http_log("getsockname() failed\n");
1760 /* XXX: should use a dynamic buffer */
1761 sdp_data_size = prepare_sdp_description(stream,
1764 if (sdp_data_size > 0) {
1765 memcpy(q, sdp_data, sdp_data_size);
1777 /* prepare output buffer */
1778 c->buffer_ptr = c->buffer;
1780 c->state = HTTPSTATE_SEND_HEADER;
1786 snprintf(msg, sizeof(msg), "ASX/RAM file not handled");
1790 stream->conns_served++;
1792 /* XXX: add there authenticate and IP match */
1795 /* if post, it means a feed is being sent */
1796 if (!stream->is_feed) {
1797 /* However it might be a status report from WMP! Let us log the
1798 * data as it might come handy one day. */
1799 const char *logline = 0;
1802 for (p = c->buffer; *p && *p != '\r' && *p != '\n'; ) {
1803 if (av_strncasecmp(p, "Pragma: log-line=", 17) == 0) {
1807 if (av_strncasecmp(p, "Pragma: client-id=", 18) == 0)
1808 client_id = strtol(p + 18, 0, 10);
1809 p = strchr(p, '\n');
1817 char *eol = strchr(logline, '\n');
1822 if (eol[-1] == '\r')
1824 http_log("%.*s\n", (int) (eol - logline), logline);
1825 c->suppress_log = 1;
1830 http_log("\nGot request:\n%s\n", c->buffer);
1833 if (client_id && extract_rates(ratebuf, sizeof(ratebuf), c->buffer)) {
1836 /* Now we have to find the client_id */
1837 for (wmpc = first_http_ctx; wmpc; wmpc = wmpc->next) {
1838 if (wmpc->wmp_client_id == client_id)
1842 if (wmpc && modify_current_stream(wmpc, ratebuf))
1843 wmpc->switch_pending = 1;
1846 snprintf(msg, sizeof(msg), "POST command not handled");
1850 if (http_start_receive_data(c) < 0) {
1851 snprintf(msg, sizeof(msg), "could not open feed");
1855 c->state = HTTPSTATE_RECEIVE_DATA;
1860 if (strcmp(stream->filename + strlen(stream->filename) - 4, ".asf") == 0)
1861 http_log("\nGot request:\n%s\n", c->buffer);
1864 if (c->stream->stream_type == STREAM_TYPE_STATUS)
1867 /* open input stream */
1868 if (open_input_stream(c, info) < 0) {
1869 snprintf(msg, sizeof(msg), "Input stream corresponding to '%s' not found", url);
1873 /* prepare HTTP header */
1875 av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.0 200 OK\r\n");
1876 mime_type = c->stream->fmt->mime_type;
1878 mime_type = "application/x-octet-stream";
1879 av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
1881 /* for asf, we need extra headers */
1882 if (!strcmp(c->stream->fmt->name,"asf_stream")) {
1883 /* Need to allocate a client id */
1885 c->wmp_client_id = av_lfg_get(&random_state);
1887 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);
1889 av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
1890 av_strlcatf(c->buffer, c->buffer_size, "\r\n");
1891 q = c->buffer + strlen(c->buffer);
1893 /* prepare output buffer */
1895 c->buffer_ptr = c->buffer;
1897 c->state = HTTPSTATE_SEND_HEADER;
1900 c->http_error = 404;
1903 snprintf(q, c->buffer_size,
1904 "HTTP/1.0 404 Not Found\r\n"
1905 "Content-type: text/html\r\n"
1908 "<head><title>404 Not Found</title></head>\n"
1912 /* prepare output buffer */
1913 c->buffer_ptr = c->buffer;
1915 c->state = HTTPSTATE_SEND_HEADER;
1919 c->http_error = 200; /* horrible : we use this value to avoid
1920 going to the send data state */
1921 c->state = HTTPSTATE_SEND_HEADER;
1925 static void fmt_bytecount(AVIOContext *pb, int64_t count)
1927 static const char suffix[] = " kMGTP";
1930 for (s = suffix; count >= 100000 && s[1]; count /= 1000, s++);
1932 avio_printf(pb, "%"PRId64"%c", count, *s);
1935 static void compute_status(HTTPContext *c)
1944 if (avio_open_dyn_buf(&pb) < 0) {
1945 /* XXX: return an error ? */
1946 c->buffer_ptr = c->buffer;
1947 c->buffer_end = c->buffer;
1951 avio_printf(pb, "HTTP/1.0 200 OK\r\n");
1952 avio_printf(pb, "Content-type: text/html\r\n");
1953 avio_printf(pb, "Pragma: no-cache\r\n");
1954 avio_printf(pb, "\r\n");
1956 avio_printf(pb, "<html><head><title>%s Status</title>\n", program_name);
1957 if (c->stream->feed_filename[0])
1958 avio_printf(pb, "<link rel=\"shortcut icon\" href=\"%s\">\n", c->stream->feed_filename);
1959 avio_printf(pb, "</head>\n<body>");
1960 avio_printf(pb, "<h1>%s Status</h1>\n", program_name);
1962 avio_printf(pb, "<h2>Available Streams</h2>\n");
1963 avio_printf(pb, "<table cellspacing=0 cellpadding=4>\n");
1964 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");
1965 stream = first_stream;
1967 char sfilename[1024];
1970 if (stream->feed != stream) {
1971 av_strlcpy(sfilename, stream->filename, sizeof(sfilename) - 10);
1972 eosf = sfilename + strlen(sfilename);
1973 if (eosf - sfilename >= 4) {
1974 if (strcmp(eosf - 4, ".asf") == 0)
1975 strcpy(eosf - 4, ".asx");
1976 else if (strcmp(eosf - 3, ".rm") == 0)
1977 strcpy(eosf - 3, ".ram");
1978 else if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
1979 /* generate a sample RTSP director if
1980 unicast. Generate an SDP redirector if
1982 eosf = strrchr(sfilename, '.');
1984 eosf = sfilename + strlen(sfilename);
1985 if (stream->is_multicast)
1986 strcpy(eosf, ".sdp");
1988 strcpy(eosf, ".rtsp");
1992 avio_printf(pb, "<tr><td><a href=\"/%s\">%s</a> ",
1993 sfilename, stream->filename);
1994 avio_printf(pb, "<td align=right> %d <td align=right> ",
1995 stream->conns_served);
1996 fmt_bytecount(pb, stream->bytes_served);
1997 switch(stream->stream_type) {
1998 case STREAM_TYPE_LIVE: {
1999 int audio_bit_rate = 0;
2000 int video_bit_rate = 0;
2001 const char *audio_codec_name = "";
2002 const char *video_codec_name = "";
2003 const char *audio_codec_name_extra = "";
2004 const char *video_codec_name_extra = "";
2006 for(i=0;i<stream->nb_streams;i++) {
2007 AVStream *st = stream->streams[i];
2008 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2009 switch(st->codec->codec_type) {
2010 case AVMEDIA_TYPE_AUDIO:
2011 audio_bit_rate += st->codec->bit_rate;
2013 if (*audio_codec_name)
2014 audio_codec_name_extra = "...";
2015 audio_codec_name = codec->name;
2018 case AVMEDIA_TYPE_VIDEO:
2019 video_bit_rate += st->codec->bit_rate;
2021 if (*video_codec_name)
2022 video_codec_name_extra = "...";
2023 video_codec_name = codec->name;
2026 case AVMEDIA_TYPE_DATA:
2027 video_bit_rate += st->codec->bit_rate;
2033 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",
2036 video_bit_rate / 1000, video_codec_name, video_codec_name_extra,
2037 audio_bit_rate / 1000, audio_codec_name, audio_codec_name_extra);
2039 avio_printf(pb, "<td>%s", stream->feed->filename);
2041 avio_printf(pb, "<td>%s", stream->feed_filename);
2042 avio_printf(pb, "\n");
2046 avio_printf(pb, "<td align=center> - <td align=right> - <td align=right> - <td><td align=right> - <td>\n");
2050 stream = stream->next;
2052 avio_printf(pb, "</table>\n");
2054 stream = first_stream;
2056 if (stream->feed == stream) {
2057 avio_printf(pb, "<h2>Feed %s</h2>", stream->filename);
2059 avio_printf(pb, "Running as pid %d.\n", stream->pid);
2066 /* This is somewhat linux specific I guess */
2067 snprintf(ps_cmd, sizeof(ps_cmd),
2068 "ps -o \"%%cpu,cputime\" --no-headers %d",
2071 pid_stat = popen(ps_cmd, "r");
2076 if (fscanf(pid_stat, "%9s %63s", cpuperc,
2078 avio_printf(pb, "Currently using %s%% of the cpu. Total time used %s.\n",
2086 avio_printf(pb, "<p>");
2088 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");
2090 for (i = 0; i < stream->nb_streams; i++) {
2091 AVStream *st = stream->streams[i];
2092 AVCodec *codec = avcodec_find_encoder(st->codec->codec_id);
2093 const char *type = "unknown";
2094 char parameters[64];
2098 switch(st->codec->codec_type) {
2099 case AVMEDIA_TYPE_AUDIO:
2101 snprintf(parameters, sizeof(parameters), "%d channel(s), %d Hz", st->codec->channels, st->codec->sample_rate);
2103 case AVMEDIA_TYPE_VIDEO:
2105 snprintf(parameters, sizeof(parameters), "%dx%d, q=%d-%d, fps=%d", st->codec->width, st->codec->height,
2106 st->codec->qmin, st->codec->qmax, st->codec->time_base.den / st->codec->time_base.num);
2111 avio_printf(pb, "<tr><td align=right>%d<td>%s<td align=right>%d<td>%s<td>%s\n",
2112 i, type, st->codec->bit_rate/1000, codec ? codec->name : "", parameters);
2114 avio_printf(pb, "</table>\n");
2117 stream = stream->next;
2120 /* connection status */
2121 avio_printf(pb, "<h2>Connection Status</h2>\n");
2123 avio_printf(pb, "Number of connections: %d / %d<br>\n",
2124 nb_connections, nb_max_connections);
2126 avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k<br>\n",
2127 current_bandwidth, max_bandwidth);
2129 avio_printf(pb, "<table>\n");
2130 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");
2131 c1 = first_http_ctx;
2139 for (j = 0; j < c1->stream->nb_streams; j++) {
2140 if (!c1->stream->feed)
2141 bitrate += c1->stream->streams[j]->codec->bit_rate;
2142 else if (c1->feed_streams[j] >= 0)
2143 bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codec->bit_rate;
2148 p = inet_ntoa(c1->from_addr.sin_addr);
2149 avio_printf(pb, "<tr><td><b>%d</b><td>%s%s<td>%s<td>%s<td>%s<td align=right>",
2151 c1->stream ? c1->stream->filename : "",
2152 c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "",
2155 http_state[c1->state]);
2156 fmt_bytecount(pb, bitrate);
2157 avio_printf(pb, "<td align=right>");
2158 fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8);
2159 avio_printf(pb, "<td align=right>");
2160 fmt_bytecount(pb, c1->data_count);
2161 avio_printf(pb, "\n");
2164 avio_printf(pb, "</table>\n");
2169 avio_printf(pb, "<hr size=1 noshade>Generated at %s", p);
2170 avio_printf(pb, "</body>\n</html>\n");
2172 len = avio_close_dyn_buf(pb, &c->pb_buffer);
2173 c->buffer_ptr = c->pb_buffer;
2174 c->buffer_end = c->pb_buffer + len;
2177 static int open_input_stream(HTTPContext *c, const char *info)
2180 char input_filename[1024];
2181 AVFormatContext *s = NULL;
2182 int buf_size, i, ret;
2185 /* find file name */
2186 if (c->stream->feed) {
2187 strcpy(input_filename, c->stream->feed->feed_filename);
2188 buf_size = FFM_PACKET_SIZE;
2189 /* compute position (absolute time) */
2190 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2191 if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) {
2192 http_log("Invalid date specification '%s' for stream\n", buf);
2195 } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) {
2196 int prebuffer = strtol(buf, 0, 10);
2197 stream_pos = av_gettime() - prebuffer * (int64_t)1000000;
2199 stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000;
2201 strcpy(input_filename, c->stream->feed_filename);
2203 /* compute position (relative time) */
2204 if (av_find_info_tag(buf, sizeof(buf), "date", info)) {
2205 if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) {
2206 http_log("Invalid date specification '%s' for stream\n", buf);
2212 if (!input_filename[0]) {
2213 http_log("No filename was specified for stream\n");
2214 return AVERROR(EINVAL);
2218 if ((ret = avformat_open_input(&s, input_filename, c->stream->ifmt, &c->stream->in_opts)) < 0) {
2219 http_log("Could not open input '%s': %s\n", input_filename, av_err2str(ret));
2223 /* set buffer size */
2224 if (buf_size > 0) ffio_set_buf_size(s->pb, buf_size);
2226 s->flags |= AVFMT_FLAG_GENPTS;
2228 if (strcmp(s->iformat->name, "ffm") &&
2229 (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) {
2230 http_log("Could not find stream info for input '%s'\n", input_filename);
2231 avformat_close_input(&s);
2235 /* choose stream as clock source (we favor the video stream if
2236 * present) for packet sending */
2237 c->pts_stream_index = 0;
2238 for(i=0;i<c->stream->nb_streams;i++) {
2239 if (c->pts_stream_index == 0 &&
2240 c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
2241 c->pts_stream_index = i;
2245 if (c->fmt_in->iformat->read_seek)
2246 av_seek_frame(c->fmt_in, -1, stream_pos, 0);
2247 /* set the start time (needed for maxtime and RTP packet timing) */
2248 c->start_time = cur_time;
2249 c->first_pts = AV_NOPTS_VALUE;
2253 /* return the server clock (in us) */
2254 static int64_t get_server_clock(HTTPContext *c)
2256 /* compute current pts value from system time */
2257 return (cur_time - c->start_time) * 1000;
2260 /* return the estimated time at which the current packet must be sent
2262 static int64_t get_packet_send_clock(HTTPContext *c)
2264 int bytes_left, bytes_sent, frame_bytes;
2266 frame_bytes = c->cur_frame_bytes;
2267 if (frame_bytes <= 0)
2270 bytes_left = c->buffer_end - c->buffer_ptr;
2271 bytes_sent = frame_bytes - bytes_left;
2272 return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes;
2277 static int http_prepare_data(HTTPContext *c)
2280 AVFormatContext *ctx;
2282 av_freep(&c->pb_buffer);
2284 case HTTPSTATE_SEND_DATA_HEADER:
2285 ctx = avformat_alloc_context();
2288 av_dict_copy(&(c->fmt_ctx.metadata), c->stream->metadata, 0);
2289 c->fmt_ctx.streams = av_mallocz_array(c->stream->nb_streams, sizeof(AVStream *));
2291 for(i=0;i<c->stream->nb_streams;i++) {
2293 c->fmt_ctx.streams[i] = av_mallocz(sizeof(AVStream));
2294 /* if file or feed, then just take streams from FFStream struct */
2295 if (!c->stream->feed ||
2296 c->stream->feed == c->stream)
2297 src = c->stream->streams[i];
2299 src = c->stream->feed->streams[c->stream->feed_streams[i]];
2301 *(c->fmt_ctx.streams[i]) = *src;
2302 c->fmt_ctx.streams[i]->priv_data = 0;
2303 /* XXX: should be done in AVStream, not in codec */
2304 c->fmt_ctx.streams[i]->codec->frame_number = 0;
2306 /* set output format parameters */
2307 c->fmt_ctx.oformat = c->stream->fmt;
2308 c->fmt_ctx.nb_streams = c->stream->nb_streams;
2310 c->got_key_frame = 0;
2312 /* prepare header and save header data in a stream */
2313 if (avio_open_dyn_buf(&c->fmt_ctx.pb) < 0) {
2314 /* XXX: potential leak */
2317 c->fmt_ctx.pb->seekable = 0;
2320 * HACK to avoid MPEG-PS muxer to spit many underflow errors
2321 * Default value from FFmpeg
2322 * Try to set it using configuration option
2324 c->fmt_ctx.max_delay = (int)(0.7*AV_TIME_BASE);
2326 if ((ret = avformat_write_header(&c->fmt_ctx, NULL)) < 0) {
2327 http_log("Error writing output header for stream '%s': %s\n",
2328 c->stream->filename, av_err2str(ret));
2331 av_dict_free(&c->fmt_ctx.metadata);
2333 len = avio_close_dyn_buf(c->fmt_ctx.pb, &c->pb_buffer);
2334 c->buffer_ptr = c->pb_buffer;
2335 c->buffer_end = c->pb_buffer + len;
2337 c->state = HTTPSTATE_SEND_DATA;
2338 c->last_packet_sent = 0;
2340 case HTTPSTATE_SEND_DATA:
2341 /* find a new packet */
2342 /* read a packet from the input stream */
2343 if (c->stream->feed)
2344 ffm_set_write_index(c->fmt_in,
2345 c->stream->feed->feed_write_index,
2346 c->stream->feed->feed_size);
2348 if (c->stream->max_time &&
2349 c->stream->max_time + c->start_time - cur_time < 0)
2350 /* We have timed out */
2351 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2355 ret = av_read_frame(c->fmt_in, &pkt);
2357 if (c->stream->feed) {
2358 /* if coming from feed, it means we reached the end of the
2359 ffm file, so must wait for more data */
2360 c->state = HTTPSTATE_WAIT_FEED;
2361 return 1; /* state changed */
2362 } else if (ret == AVERROR(EAGAIN)) {
2363 /* input not ready, come back later */
2366 if (c->stream->loop) {
2367 avformat_close_input(&c->fmt_in);
2368 if (open_input_stream(c, "") < 0)
2373 /* must send trailer now because EOF or error */
2374 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2378 int source_index = pkt.stream_index;
2379 /* update first pts if needed */
2380 if (c->first_pts == AV_NOPTS_VALUE) {
2381 c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q);
2382 c->start_time = cur_time;
2384 /* send it to the appropriate stream */
2385 if (c->stream->feed) {
2386 /* if coming from a feed, select the right stream */
2387 if (c->switch_pending) {
2388 c->switch_pending = 0;
2389 for(i=0;i<c->stream->nb_streams;i++) {
2390 if (c->switch_feed_streams[i] == pkt.stream_index)
2391 if (pkt.flags & AV_PKT_FLAG_KEY)
2392 c->switch_feed_streams[i] = -1;
2393 if (c->switch_feed_streams[i] >= 0)
2394 c->switch_pending = 1;
2397 for(i=0;i<c->stream->nb_streams;i++) {
2398 if (c->stream->feed_streams[i] == pkt.stream_index) {
2399 AVStream *st = c->fmt_in->streams[source_index];
2400 pkt.stream_index = i;
2401 if (pkt.flags & AV_PKT_FLAG_KEY &&
2402 (st->codec->codec_type == AVMEDIA_TYPE_VIDEO ||
2403 c->stream->nb_streams == 1))
2404 c->got_key_frame = 1;
2405 if (!c->stream->send_on_key || c->got_key_frame)
2410 AVCodecContext *codec;
2411 AVStream *ist, *ost;
2413 ist = c->fmt_in->streams[source_index];
2414 /* specific handling for RTP: we use several
2415 * output streams (one for each RTP connection).
2416 * XXX: need more abstract handling */
2417 if (c->is_packetized) {
2418 /* compute send time and duration */
2419 c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q);
2420 c->cur_pts -= c->first_pts;
2421 c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q);
2422 /* find RTP context */
2423 c->packet_stream_index = pkt.stream_index;
2424 ctx = c->rtp_ctx[c->packet_stream_index];
2426 av_free_packet(&pkt);
2429 codec = ctx->streams[0]->codec;
2430 /* only one stream per RTP connection */
2431 pkt.stream_index = 0;
2435 codec = ctx->streams[pkt.stream_index]->codec;
2438 if (c->is_packetized) {
2439 int max_packet_size;
2440 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP)
2441 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
2443 max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size;
2444 ret = ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size);
2446 ret = avio_open_dyn_buf(&ctx->pb);
2449 /* XXX: potential leak */
2452 ost = ctx->streams[pkt.stream_index];
2454 ctx->pb->seekable = 0;
2455 if (pkt.dts != AV_NOPTS_VALUE)
2456 pkt.dts = av_rescale_q(pkt.dts, ist->time_base, ost->time_base);
2457 if (pkt.pts != AV_NOPTS_VALUE)
2458 pkt.pts = av_rescale_q(pkt.pts, ist->time_base, ost->time_base);
2459 pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
2460 if ((ret = av_write_frame(ctx, &pkt)) < 0) {
2461 http_log("Error writing frame to output for stream '%s': %s\n",
2462 c->stream->filename, av_err2str(ret));
2463 c->state = HTTPSTATE_SEND_DATA_TRAILER;
2466 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2467 c->cur_frame_bytes = len;
2468 c->buffer_ptr = c->pb_buffer;
2469 c->buffer_end = c->pb_buffer + len;
2471 codec->frame_number++;
2473 av_free_packet(&pkt);
2477 av_free_packet(&pkt);
2482 case HTTPSTATE_SEND_DATA_TRAILER:
2483 /* last packet test ? */
2484 if (c->last_packet_sent || c->is_packetized)
2487 /* prepare header */
2488 if (avio_open_dyn_buf(&ctx->pb) < 0) {
2489 /* XXX: potential leak */
2492 c->fmt_ctx.pb->seekable = 0;
2493 av_write_trailer(ctx);
2494 len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer);
2495 c->buffer_ptr = c->pb_buffer;
2496 c->buffer_end = c->pb_buffer + len;
2498 c->last_packet_sent = 1;
2504 /* should convert the format at the same time */
2505 /* send data starting at c->buffer_ptr to the output connection
2506 * (either UDP or TCP) */
2507 static int http_send_data(HTTPContext *c)
2512 if (c->buffer_ptr >= c->buffer_end) {
2513 ret = http_prepare_data(c);
2517 /* state change requested */
2520 if (c->is_packetized) {
2521 /* RTP data output */
2522 len = c->buffer_end - c->buffer_ptr;
2524 /* fail safe - should never happen */
2526 c->buffer_ptr = c->buffer_end;
2529 len = (c->buffer_ptr[0] << 24) |
2530 (c->buffer_ptr[1] << 16) |
2531 (c->buffer_ptr[2] << 8) |
2533 if (len > (c->buffer_end - c->buffer_ptr))
2535 if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) {
2536 /* nothing to send yet: we can wait */
2540 c->data_count += len;
2541 update_datarate(&c->datarate, c->data_count);
2543 c->stream->bytes_served += len;
2545 if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) {
2546 /* RTP packets are sent inside the RTSP TCP connection */
2548 int interleaved_index, size;
2550 HTTPContext *rtsp_c;
2553 /* if no RTSP connection left, error */
2556 /* if already sending something, then wait. */
2557 if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST)
2559 if (avio_open_dyn_buf(&pb) < 0)
2561 interleaved_index = c->packet_stream_index * 2;
2562 /* RTCP packets are sent at odd indexes */
2563 if (c->buffer_ptr[1] == 200)
2564 interleaved_index++;
2565 /* write RTSP TCP header */
2567 header[1] = interleaved_index;
2568 header[2] = len >> 8;
2570 avio_write(pb, header, 4);
2571 /* write RTP packet data */
2573 avio_write(pb, c->buffer_ptr, len);
2574 size = avio_close_dyn_buf(pb, &c->packet_buffer);
2575 /* prepare asynchronous TCP sending */
2576 rtsp_c->packet_buffer_ptr = c->packet_buffer;
2577 rtsp_c->packet_buffer_end = c->packet_buffer + size;
2578 c->buffer_ptr += len;
2580 /* send everything we can NOW */
2581 len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr,
2582 rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0);
2584 rtsp_c->packet_buffer_ptr += len;
2585 if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) {
2586 /* if we could not send all the data, we will
2587 send it later, so a new state is needed to
2588 "lock" the RTSP TCP connection */
2589 rtsp_c->state = RTSPSTATE_SEND_PACKET;
2592 /* all data has been sent */
2593 av_freep(&c->packet_buffer);
2595 /* send RTP packet directly in UDP */
2597 ffurl_write(c->rtp_handles[c->packet_stream_index],
2598 c->buffer_ptr, len);
2599 c->buffer_ptr += len;
2600 /* here we continue as we can send several packets per 10 ms slot */
2603 /* TCP data output */
2604 len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
2606 if (ff_neterrno() != AVERROR(EAGAIN) &&
2607 ff_neterrno() != AVERROR(EINTR))
2608 /* error : close connection */
2613 c->buffer_ptr += len;
2615 c->data_count += len;
2616 update_datarate(&c->datarate, c->data_count);
2618 c->stream->bytes_served += len;
2626 static int http_start_receive_data(HTTPContext *c)
2631 if (c->stream->feed_opened) {
2632 http_log("Stream feed '%s' was not opened\n", c->stream->feed_filename);
2633 return AVERROR(EINVAL);
2636 /* Don't permit writing to this one */
2637 if (c->stream->readonly) {
2638 http_log("Cannot write to read-only file '%s'\n", c->stream->feed_filename);
2639 return AVERROR(EINVAL);
2643 fd = open(c->stream->feed_filename, O_RDWR);
2645 ret = AVERROR(errno);
2646 http_log("Could not open feed file '%s': %s\n",
2647 c->stream->feed_filename, strerror(errno));
2652 if (c->stream->truncate) {
2653 /* truncate feed file */
2654 ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE);
2655 http_log("Truncating feed file '%s'\n", c->stream->feed_filename);
2656 if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) {
2657 ret = AVERROR(errno);
2658 http_log("Error truncating feed file '%s': %s\n",
2659 c->stream->feed_filename, strerror(errno));
2663 ret = ffm_read_write_index(fd);
2665 http_log("Error reading write index from feed file '%s': %s\n",
2666 c->stream->feed_filename, strerror(errno));
2669 c->stream->feed_write_index = ret;
2673 c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
2674 c->stream->feed_size = lseek(fd, 0, SEEK_END);
2675 lseek(fd, 0, SEEK_SET);
2677 /* init buffer input */
2678 c->buffer_ptr = c->buffer;
2679 c->buffer_end = c->buffer + FFM_PACKET_SIZE;
2680 c->stream->feed_opened = 1;
2681 c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked");
2685 static int http_receive_data(HTTPContext *c)
2688 int len, loop_run = 0;
2690 while (c->chunked_encoding && !c->chunk_size &&
2691 c->buffer_end > c->buffer_ptr) {
2692 /* read chunk header, if present */
2693 len = recv(c->fd, c->buffer_ptr, 1, 0);
2696 if (ff_neterrno() != AVERROR(EAGAIN) &&
2697 ff_neterrno() != AVERROR(EINTR))
2698 /* error : close connection */
2701 } else if (len == 0) {
2702 /* end of connection : close it */
2704 } else if (c->buffer_ptr - c->buffer >= 2 &&
2705 !memcmp(c->buffer_ptr - 1, "\r\n", 2)) {
2706 c->chunk_size = strtol(c->buffer, 0, 16);
2707 if (c->chunk_size == 0) // end of stream
2709 c->buffer_ptr = c->buffer;
2711 } else if (++loop_run > 10) {
2712 /* no chunk header, abort */
2719 if (c->buffer_end > c->buffer_ptr) {
2720 len = recv(c->fd, c->buffer_ptr,
2721 FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0);
2723 if (ff_neterrno() != AVERROR(EAGAIN) &&
2724 ff_neterrno() != AVERROR(EINTR))
2725 /* error : close connection */
2727 } else if (len == 0)
2728 /* end of connection : close it */
2731 c->chunk_size -= len;
2732 c->buffer_ptr += len;
2733 c->data_count += len;
2734 update_datarate(&c->datarate, c->data_count);
2738 if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) {
2739 if (c->buffer[0] != 'f' ||
2740 c->buffer[1] != 'm') {
2741 http_log("Feed stream has become desynchronized -- disconnecting\n");
2746 if (c->buffer_ptr >= c->buffer_end) {
2747 FFStream *feed = c->stream;
2748 /* a packet has been received : write it in the store, except
2750 if (c->data_count > FFM_PACKET_SIZE) {
2751 /* XXX: use llseek or url_seek
2752 * XXX: Should probably fail? */
2753 if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1)
2754 http_log("Seek to %"PRId64" failed\n", feed->feed_write_index);
2756 if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) {
2757 http_log("Error writing to feed file: %s\n", strerror(errno));
2761 feed->feed_write_index += FFM_PACKET_SIZE;
2762 /* update file size */
2763 if (feed->feed_write_index > c->stream->feed_size)
2764 feed->feed_size = feed->feed_write_index;
2766 /* handle wrap around if max file size reached */
2767 if (c->stream->feed_max_size && feed->feed_write_index >= c->stream->feed_max_size)
2768 feed->feed_write_index = FFM_PACKET_SIZE;
2771 if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) {
2772 http_log("Error writing index to feed file: %s\n", strerror(errno));
2776 /* wake up any waiting connections */
2777 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2778 if (c1->state == HTTPSTATE_WAIT_FEED &&
2779 c1->stream->feed == c->stream->feed)
2780 c1->state = HTTPSTATE_SEND_DATA;
2783 /* We have a header in our hands that contains useful data */
2784 AVFormatContext *s = avformat_alloc_context();
2786 AVInputFormat *fmt_in;
2792 /* use feed output format name to find corresponding input format */
2793 fmt_in = av_find_input_format(feed->fmt->name);
2797 pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer,
2798 0, NULL, NULL, NULL, NULL);
2802 if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) {
2807 /* Now we have the actual streams */
2808 if (s->nb_streams != feed->nb_streams) {
2809 avformat_close_input(&s);
2811 http_log("Feed '%s' stream number does not match registered feed\n",
2812 c->stream->feed_filename);
2816 for (i = 0; i < s->nb_streams; i++) {
2817 AVStream *fst = feed->streams[i];
2818 AVStream *st = s->streams[i];
2819 avcodec_copy_context(fst->codec, st->codec);
2822 avformat_close_input(&s);
2825 c->buffer_ptr = c->buffer;
2830 c->stream->feed_opened = 0;
2832 /* wake up any waiting connections to stop waiting for feed */
2833 for(c1 = first_http_ctx; c1; c1 = c1->next) {
2834 if (c1->state == HTTPSTATE_WAIT_FEED &&
2835 c1->stream->feed == c->stream->feed)
2836 c1->state = HTTPSTATE_SEND_DATA_TRAILER;
2841 /********************************************************************/
2844 static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number)
2851 str = RTSP_STATUS_CODE2STRING(error_number);
2853 str = "Unknown Error";
2855 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str);
2856 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
2858 /* output GMT time */
2861 strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm);
2862 avio_printf(c->pb, "Date: %s GMT\r\n", buf2);
2865 static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number)
2867 rtsp_reply_header(c, error_number);
2868 avio_printf(c->pb, "\r\n");
2871 static int rtsp_parse_request(HTTPContext *c)
2873 const char *p, *p1, *p2;
2879 RTSPMessageHeader header1 = { 0 }, *header = &header1;
2881 c->buffer_ptr[0] = '\0';
2884 get_word(cmd, sizeof(cmd), &p);
2885 get_word(url, sizeof(url), &p);
2886 get_word(protocol, sizeof(protocol), &p);
2888 av_strlcpy(c->method, cmd, sizeof(c->method));
2889 av_strlcpy(c->url, url, sizeof(c->url));
2890 av_strlcpy(c->protocol, protocol, sizeof(c->protocol));
2892 if (avio_open_dyn_buf(&c->pb) < 0) {
2893 /* XXX: cannot do more */
2894 c->pb = NULL; /* safety */
2898 /* check version name */
2899 if (strcmp(protocol, "RTSP/1.0") != 0) {
2900 rtsp_reply_error(c, RTSP_STATUS_VERSION);
2904 /* parse each header line */
2905 /* skip to next line */
2906 while (*p != '\n' && *p != '\0')
2910 while (*p != '\0') {
2911 p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
2915 if (p2 > p && p2[-1] == '\r')
2917 /* skip empty line */
2921 if (len > sizeof(line) - 1)
2922 len = sizeof(line) - 1;
2923 memcpy(line, p, len);
2925 ff_rtsp_parse_line(header, line, NULL, NULL);
2929 /* handle sequence number */
2930 c->seq = header->seq;
2932 if (!strcmp(cmd, "DESCRIBE"))
2933 rtsp_cmd_describe(c, url);
2934 else if (!strcmp(cmd, "OPTIONS"))
2935 rtsp_cmd_options(c, url);
2936 else if (!strcmp(cmd, "SETUP"))
2937 rtsp_cmd_setup(c, url, header);
2938 else if (!strcmp(cmd, "PLAY"))
2939 rtsp_cmd_play(c, url, header);
2940 else if (!strcmp(cmd, "PAUSE"))
2941 rtsp_cmd_interrupt(c, url, header, 1);
2942 else if (!strcmp(cmd, "TEARDOWN"))
2943 rtsp_cmd_interrupt(c, url, header, 0);
2945 rtsp_reply_error(c, RTSP_STATUS_METHOD);
2948 len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
2949 c->pb = NULL; /* safety */
2951 /* XXX: cannot do more */
2954 c->buffer_ptr = c->pb_buffer;
2955 c->buffer_end = c->pb_buffer + len;
2956 c->state = RTSPSTATE_SEND_REPLY;
2960 static int prepare_sdp_description(FFStream *stream, uint8_t **pbuffer,
2961 struct in_addr my_ip)
2963 AVFormatContext *avc;
2964 AVStream *avs = NULL;
2965 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL);
2966 AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0);
2971 avc = avformat_alloc_context();
2972 if (!avc || !rtp_format) {
2975 avc->oformat = rtp_format;
2976 av_dict_set(&avc->metadata, "title",
2977 entry ? entry->value : "No Title", 0);
2978 avc->nb_streams = stream->nb_streams;
2979 if (stream->is_multicast) {
2980 snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d",
2981 inet_ntoa(stream->multicast_ip),
2982 stream->multicast_port, stream->multicast_ttl);
2984 snprintf(avc->filename, 1024, "rtp://0.0.0.0");
2987 if (avc->nb_streams >= INT_MAX/sizeof(*avc->streams) ||
2988 !(avc->streams = av_malloc(avc->nb_streams * sizeof(*avc->streams))))
2990 if (avc->nb_streams >= INT_MAX/sizeof(*avs) ||
2991 !(avs = av_malloc(avc->nb_streams * sizeof(*avs))))
2994 for(i = 0; i < stream->nb_streams; i++) {
2995 avc->streams[i] = &avs[i];
2996 avc->streams[i]->codec = stream->streams[i]->codec;
2998 *pbuffer = av_mallocz(2048);
2999 av_sdp_create(&avc, 1, *pbuffer, 2048);
3002 av_freep(&avc->streams);
3003 av_dict_free(&avc->metadata);
3007 return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM);
3010 static void rtsp_cmd_options(HTTPContext *c, const char *url)
3012 // rtsp_reply_header(c, RTSP_STATUS_OK);
3013 avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
3014 avio_printf(c->pb, "CSeq: %d\r\n", c->seq);
3015 avio_printf(c->pb, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
3016 avio_printf(c->pb, "\r\n");
3019 static void rtsp_cmd_describe(HTTPContext *c, const char *url)
3027 struct sockaddr_in my_addr;
3029 /* find which URL is asked */
3030 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3035 for(stream = first_stream; stream; stream = stream->next) {
3036 if (!stream->is_feed &&
3037 stream->fmt && !strcmp(stream->fmt->name, "rtp") &&
3038 !strcmp(path, stream->filename)) {
3042 /* no stream found */
3043 rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND);
3047 /* prepare the media description in SDP format */
3049 /* get the host IP */
3050 len = sizeof(my_addr);
3051 getsockname(c->fd, (struct sockaddr *)&my_addr, &len);
3052 content_length = prepare_sdp_description(stream, &content, my_addr.sin_addr);
3053 if (content_length < 0) {
3054 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3057 rtsp_reply_header(c, RTSP_STATUS_OK);
3058 avio_printf(c->pb, "Content-Base: %s/\r\n", url);
3059 avio_printf(c->pb, "Content-Type: application/sdp\r\n");
3060 avio_printf(c->pb, "Content-Length: %d\r\n", content_length);
3061 avio_printf(c->pb, "\r\n");
3062 avio_write(c->pb, content, content_length);
3066 static HTTPContext *find_rtp_session(const char *session_id)
3070 if (session_id[0] == '\0')
3073 for(c = first_http_ctx; c; c = c->next) {
3074 if (!strcmp(c->session_id, session_id))
3080 static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport)
3082 RTSPTransportField *th;
3085 for(i=0;i<h->nb_transports;i++) {
3086 th = &h->transports[i];
3087 if (th->lower_transport == lower_transport)
3093 static void rtsp_cmd_setup(HTTPContext *c, const char *url,
3094 RTSPMessageHeader *h)
3097 int stream_index, rtp_port, rtcp_port;
3102 RTSPTransportField *th;
3103 struct sockaddr_in dest_addr;
3104 RTSPActionServerSetup setup;
3106 /* find which URL is asked */
3107 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3112 /* now check each stream */
3113 for(stream = first_stream; stream; stream = stream->next) {
3114 if (!stream->is_feed &&
3115 stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3116 /* accept aggregate filenames only if single stream */
3117 if (!strcmp(path, stream->filename)) {
3118 if (stream->nb_streams != 1) {
3119 rtsp_reply_error(c, RTSP_STATUS_AGGREGATE);
3126 for(stream_index = 0; stream_index < stream->nb_streams;
3128 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3129 stream->filename, stream_index);
3130 if (!strcmp(path, buf))
3135 /* no stream found */
3136 rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */
3140 /* generate session id if needed */
3141 if (h->session_id[0] == '\0') {
3142 unsigned random0 = av_lfg_get(&random_state);
3143 unsigned random1 = av_lfg_get(&random_state);
3144 snprintf(h->session_id, sizeof(h->session_id), "%08x%08x",
3148 /* find RTP session, and create it if none found */
3149 rtp_c = find_rtp_session(h->session_id);
3151 /* always prefer UDP */
3152 th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP);
3154 th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
3156 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3161 rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id,
3162 th->lower_transport);
3164 rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH);
3168 /* open input stream */
3169 if (open_input_stream(rtp_c, "") < 0) {
3170 rtsp_reply_error(c, RTSP_STATUS_INTERNAL);
3175 /* test if stream is OK (test needed because several SETUP needs
3176 to be done for a given file) */
3177 if (rtp_c->stream != stream) {
3178 rtsp_reply_error(c, RTSP_STATUS_SERVICE);
3182 /* test if stream is already set up */
3183 if (rtp_c->rtp_ctx[stream_index]) {
3184 rtsp_reply_error(c, RTSP_STATUS_STATE);
3188 /* check transport */
3189 th = find_transport(h, rtp_c->rtp_protocol);
3190 if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP &&
3191 th->client_port_min <= 0)) {
3192 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3196 /* setup default options */
3197 setup.transport_option[0] = '\0';
3198 dest_addr = rtp_c->from_addr;
3199 dest_addr.sin_port = htons(th->client_port_min);
3202 if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) {
3203 rtsp_reply_error(c, RTSP_STATUS_TRANSPORT);
3207 /* now everything is OK, so we can send the connection parameters */
3208 rtsp_reply_header(c, RTSP_STATUS_OK);
3210 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3212 switch(rtp_c->rtp_protocol) {
3213 case RTSP_LOWER_TRANSPORT_UDP:
3214 rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]);
3215 rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]);
3216 avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;"
3217 "client_port=%d-%d;server_port=%d-%d",
3218 th->client_port_min, th->client_port_max,
3219 rtp_port, rtcp_port);
3221 case RTSP_LOWER_TRANSPORT_TCP:
3222 avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d",
3223 stream_index * 2, stream_index * 2 + 1);
3228 if (setup.transport_option[0] != '\0')
3229 avio_printf(c->pb, ";%s", setup.transport_option);
3230 avio_printf(c->pb, "\r\n");
3233 avio_printf(c->pb, "\r\n");
3237 /* find an RTP connection by using the session ID. Check consistency
3239 static HTTPContext *find_rtp_session_with_url(const char *url,
3240 const char *session_id)
3248 rtp_c = find_rtp_session(session_id);
3252 /* find which URL is asked */
3253 av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url);
3257 if(!strcmp(path, rtp_c->stream->filename)) return rtp_c;
3258 for(s=0; s<rtp_c->stream->nb_streams; ++s) {
3259 snprintf(buf, sizeof(buf), "%s/streamid=%d",
3260 rtp_c->stream->filename, s);
3261 if(!strncmp(path, buf, sizeof(buf))) {
3262 // XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE if nb_streams>1?
3267 if (len > 0 && path[len - 1] == '/' &&
3268 !strncmp(path, rtp_c->stream->filename, len - 1))
3273 static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h)
3277 rtp_c = find_rtp_session_with_url(url, h->session_id);
3279 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3283 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3284 rtp_c->state != HTTPSTATE_WAIT_FEED &&
3285 rtp_c->state != HTTPSTATE_READY) {
3286 rtsp_reply_error(c, RTSP_STATUS_STATE);
3290 rtp_c->state = HTTPSTATE_SEND_DATA;
3292 /* now everything is OK, so we can send the connection parameters */
3293 rtsp_reply_header(c, RTSP_STATUS_OK);
3295 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3296 avio_printf(c->pb, "\r\n");
3299 static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, RTSPMessageHeader *h, int pause_only)
3303 rtp_c = find_rtp_session_with_url(url, h->session_id);
3305 rtsp_reply_error(c, RTSP_STATUS_SESSION);
3310 if (rtp_c->state != HTTPSTATE_SEND_DATA &&
3311 rtp_c->state != HTTPSTATE_WAIT_FEED) {
3312 rtsp_reply_error(c, RTSP_STATUS_STATE);
3315 rtp_c->state = HTTPSTATE_READY;
3316 rtp_c->first_pts = AV_NOPTS_VALUE;
3319 /* now everything is OK, so we can send the connection parameters */
3320 rtsp_reply_header(c, RTSP_STATUS_OK);
3322 avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id);
3323 avio_printf(c->pb, "\r\n");
3326 close_connection(rtp_c);
3329 /********************************************************************/
3332 static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr,
3333 FFStream *stream, const char *session_id,
3334 enum RTSPLowerTransport rtp_protocol)
3336 HTTPContext *c = NULL;
3337 const char *proto_str;
3339 /* XXX: should output a warning page when coming
3340 close to the connection limit */
3341 if (nb_connections >= nb_max_connections)
3344 /* add a new connection */
3345 c = av_mallocz(sizeof(HTTPContext));
3350 c->poll_entry = NULL;
3351 c->from_addr = *from_addr;
3352 c->buffer_size = IOBUFFER_INIT_SIZE;
3353 c->buffer = av_malloc(c->buffer_size);
3358 av_strlcpy(c->session_id, session_id, sizeof(c->session_id));
3359 c->state = HTTPSTATE_READY;
3360 c->is_packetized = 1;
3361 c->rtp_protocol = rtp_protocol;
3363 /* protocol is shown in statistics */
3364 switch(c->rtp_protocol) {
3365 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3366 proto_str = "MCAST";
3368 case RTSP_LOWER_TRANSPORT_UDP:
3371 case RTSP_LOWER_TRANSPORT_TCP:
3378 av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol));
3379 av_strlcat(c->protocol, proto_str, sizeof(c->protocol));
3381 current_bandwidth += stream->bandwidth;
3383 c->next = first_http_ctx;
3389 av_freep(&c->buffer);
3395 /* add a new RTP stream in an RTP connection (used in RTSP SETUP
3396 command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is
3398 static int rtp_new_av_stream(HTTPContext *c,
3399 int stream_index, struct sockaddr_in *dest_addr,
3400 HTTPContext *rtsp_c)
3402 AVFormatContext *ctx;
3405 URLContext *h = NULL;
3407 int max_packet_size;
3409 /* now we can open the relevant output stream */
3410 ctx = avformat_alloc_context();
3413 ctx->oformat = av_guess_format("rtp", NULL, NULL);
3415 st = av_mallocz(sizeof(AVStream));
3418 ctx->nb_streams = 1;
3419 ctx->streams = av_mallocz_array(ctx->nb_streams, sizeof(AVStream *));
3422 ctx->streams[0] = st;
3424 if (!c->stream->feed ||
3425 c->stream->feed == c->stream)
3426 memcpy(st, c->stream->streams[stream_index], sizeof(AVStream));
3429 c->stream->feed->streams[c->stream->feed_streams[stream_index]],
3431 st->priv_data = NULL;
3433 /* build destination RTP address */
3434 ipaddr = inet_ntoa(dest_addr->sin_addr);
3436 switch(c->rtp_protocol) {
3437 case RTSP_LOWER_TRANSPORT_UDP:
3438 case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:
3441 /* XXX: also pass as parameter to function ? */
3442 if (c->stream->is_multicast) {
3444 ttl = c->stream->multicast_ttl;
3447 snprintf(ctx->filename, sizeof(ctx->filename),
3448 "rtp://%s:%d?multicast=1&ttl=%d",
3449 ipaddr, ntohs(dest_addr->sin_port), ttl);
3451 snprintf(ctx->filename, sizeof(ctx->filename),
3452 "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port));
3455 if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0)
3457 c->rtp_handles[stream_index] = h;
3458 max_packet_size = h->max_packet_size;
3460 case RTSP_LOWER_TRANSPORT_TCP:
3463 max_packet_size = RTSP_TCP_MAX_PACKET_SIZE;
3469 http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n",
3470 ipaddr, ntohs(dest_addr->sin_port),
3471 c->stream->filename, stream_index, c->protocol);
3473 /* normally, no packets should be output here, but the packet size may
3475 if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) {
3476 /* XXX: close stream */
3479 if (avformat_write_header(ctx, NULL) < 0) {
3487 avio_close_dyn_buf(ctx->pb, &dummy_buf);
3490 c->rtp_ctx[stream_index] = ctx;
3494 /********************************************************************/
3495 /* ffserver initialization */
3497 static AVStream *add_av_stream1(FFStream *stream, AVCodecContext *codec, int copy)
3501 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3504 fst = av_mallocz(sizeof(AVStream));
3508 fst->codec = avcodec_alloc_context3(NULL);
3509 memcpy(fst->codec, codec, sizeof(AVCodecContext));
3510 if (codec->extradata_size) {
3511 fst->codec->extradata = av_mallocz(codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
3512 memcpy(fst->codec->extradata, codec->extradata,
3513 codec->extradata_size);
3516 /* live streams must use the actual feed's codec since it may be
3517 * updated later to carry extradata needed by them.
3521 fst->priv_data = av_mallocz(sizeof(FeedData));
3522 fst->index = stream->nb_streams;
3523 avpriv_set_pts_info(fst, 33, 1, 90000);
3524 fst->sample_aspect_ratio = codec->sample_aspect_ratio;
3525 stream->streams[stream->nb_streams++] = fst;
3529 /* return the stream number in the feed */
3530 static int add_av_stream(FFStream *feed, AVStream *st)
3533 AVCodecContext *av, *av1;
3537 for(i=0;i<feed->nb_streams;i++) {
3538 st = feed->streams[i];
3540 if (av1->codec_id == av->codec_id &&
3541 av1->codec_type == av->codec_type &&
3542 av1->bit_rate == av->bit_rate) {
3544 switch(av->codec_type) {
3545 case AVMEDIA_TYPE_AUDIO:
3546 if (av1->channels == av->channels &&
3547 av1->sample_rate == av->sample_rate)
3550 case AVMEDIA_TYPE_VIDEO:
3551 if (av1->width == av->width &&
3552 av1->height == av->height &&
3553 av1->time_base.den == av->time_base.den &&
3554 av1->time_base.num == av->time_base.num &&
3555 av1->gop_size == av->gop_size)
3564 fst = add_av_stream1(feed, av, 0);
3567 return feed->nb_streams - 1;
3570 static void remove_stream(FFStream *stream)
3582 /* specific MPEG4 handling : we extract the raw parameters */
3583 static void extract_mpeg4_header(AVFormatContext *infile)
3585 int mpeg4_count, i, size;
3590 infile->flags |= AVFMT_FLAG_NOFILLIN | AVFMT_FLAG_NOPARSE;
3593 for(i=0;i<infile->nb_streams;i++) {
3594 st = infile->streams[i];
3595 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3596 st->codec->extradata_size == 0) {
3603 printf("MPEG4 without extra data: trying to find header in %s\n", infile->filename);
3604 while (mpeg4_count > 0) {
3605 if (av_read_frame(infile, &pkt) < 0)
3607 st = infile->streams[pkt.stream_index];
3608 if (st->codec->codec_id == AV_CODEC_ID_MPEG4 &&
3609 st->codec->extradata_size == 0) {
3610 av_freep(&st->codec->extradata);
3611 /* fill extradata with the header */
3612 /* XXX: we make hard suppositions here ! */
3614 while (p < pkt.data + pkt.size - 4) {
3615 /* stop when vop header is found */
3616 if (p[0] == 0x00 && p[1] == 0x00 &&
3617 p[2] == 0x01 && p[3] == 0xb6) {
3618 size = p - pkt.data;
3619 // av_hex_dump_log(infile, AV_LOG_DEBUG, pkt.data, size);
3620 st->codec->extradata = av_mallocz(size + FF_INPUT_BUFFER_PADDING_SIZE);
3621 st->codec->extradata_size = size;
3622 memcpy(st->codec->extradata, pkt.data, size);
3629 av_free_packet(&pkt);
3633 /* compute the needed AVStream for each file */
3634 static void build_file_streams(void)
3636 FFStream *stream, *stream_next;
3639 /* gather all streams */
3640 for(stream = first_stream; stream; stream = stream_next) {
3641 AVFormatContext *infile = NULL;
3642 stream_next = stream->next;
3643 if (stream->stream_type == STREAM_TYPE_LIVE &&
3645 /* the stream comes from a file */
3646 /* try to open the file */
3648 if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) {
3649 /* specific case : if transport stream output to RTP,
3650 we use a raw transport stream reader */
3651 av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0);
3654 if (!stream->feed_filename[0]) {
3655 http_log("Unspecified feed file for stream '%s'\n", stream->filename);
3659 http_log("Opening feed file '%s' for stream '%s'\n", stream->feed_filename, stream->filename);
3660 if ((ret = avformat_open_input(&infile, stream->feed_filename, stream->ifmt, &stream->in_opts)) < 0) {
3661 http_log("Could not open '%s': %s\n", stream->feed_filename, av_err2str(ret));
3662 /* remove stream (no need to spend more time on it) */
3664 remove_stream(stream);
3666 /* find all the AVStreams inside and reference them in
3668 if (avformat_find_stream_info(infile, NULL) < 0) {
3669 http_log("Could not find codec parameters from '%s'\n",
3670 stream->feed_filename);
3671 avformat_close_input(&infile);
3674 extract_mpeg4_header(infile);
3676 for(i=0;i<infile->nb_streams;i++)
3677 add_av_stream1(stream, infile->streams[i]->codec, 1);
3679 avformat_close_input(&infile);
3685 /* compute the needed AVStream for each feed */
3686 static void build_feed_streams(void)
3688 FFStream *stream, *feed;
3691 /* gather all streams */
3692 for(stream = first_stream; stream; stream = stream->next) {
3693 feed = stream->feed;
3695 if (stream->is_feed) {
3696 for(i=0;i<stream->nb_streams;i++)
3697 stream->feed_streams[i] = i;
3699 /* we handle a stream coming from a feed */
3700 for(i=0;i<stream->nb_streams;i++)
3701 stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]);
3706 /* create feed files if needed */
3707 for(feed = first_feed; feed; feed = feed->next_feed) {
3710 if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) {
3711 /* See if it matches */
3712 AVFormatContext *s = NULL;
3715 if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) >= 0) {
3716 /* set buffer size */
3717 ffio_set_buf_size(s->pb, FFM_PACKET_SIZE);
3718 /* Now see if it matches */
3719 if (s->nb_streams == feed->nb_streams) {
3721 for(i=0;i<s->nb_streams;i++) {
3723 sf = feed->streams[i];
3726 if (sf->index != ss->index ||
3728 http_log("Index & Id do not match for stream %d (%s)\n",
3729 i, feed->feed_filename);
3732 AVCodecContext *ccf, *ccs;
3736 #define CHECK_CODEC(x) (ccf->x != ccs->x)
3738 if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) {
3739 http_log("Codecs do not match for stream %d\n", i);
3741 } else if (CHECK_CODEC(bit_rate) || CHECK_CODEC(flags)) {
3742 http_log("Codec bitrates do not match for stream %d\n", i);
3744 } else if (ccf->codec_type == AVMEDIA_TYPE_VIDEO) {
3745 if (CHECK_CODEC(time_base.den) ||
3746 CHECK_CODEC(time_base.num) ||
3747 CHECK_CODEC(width) ||
3748 CHECK_CODEC(height)) {
3749 http_log("Codec width, height and framerate do not match for stream %d\n", i);
3752 } else if (ccf->codec_type == AVMEDIA_TYPE_AUDIO) {
3753 if (CHECK_CODEC(sample_rate) ||
3754 CHECK_CODEC(channels) ||
3755 CHECK_CODEC(frame_size)) {
3756 http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", i);
3760 http_log("Unknown codec type\n");
3768 http_log("Deleting feed file '%s' as stream counts differ (%d != %d)\n",
3769 feed->feed_filename, s->nb_streams, feed->nb_streams);
3771 avformat_close_input(&s);
3773 http_log("Deleting feed file '%s' as it appears to be corrupt\n",
3774 feed->feed_filename);
3777 if (feed->readonly) {
3778 http_log("Unable to delete feed file '%s' as it is marked readonly\n",
3779 feed->feed_filename);
3782 unlink(feed->feed_filename);
3785 if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) {
3786 AVFormatContext *s = avformat_alloc_context();
3788 if (feed->readonly) {
3789 http_log("Unable to create feed file '%s' as it is marked readonly\n",
3790 feed->feed_filename);
3794 /* only write the header of the ffm file */
3795 if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) {
3796 http_log("Could not open output feed file '%s'\n",
3797 feed->feed_filename);
3800 s->oformat = feed->fmt;
3801 s->nb_streams = feed->nb_streams;
3802 s->streams = feed->streams;
3803 if (avformat_write_header(s, NULL) < 0) {
3804 http_log("Container doesn't support the required parameters\n");
3807 /* XXX: need better API */
3808 av_freep(&s->priv_data);
3812 avformat_free_context(s);
3814 /* get feed size and write index */
3815 fd = open(feed->feed_filename, O_RDONLY);
3817 http_log("Could not open output feed file '%s'\n",
3818 feed->feed_filename);
3822 feed->feed_write_index = FFMAX(ffm_read_write_index(fd), FFM_PACKET_SIZE);
3823 feed->feed_size = lseek(fd, 0, SEEK_END);
3824 /* ensure that we do not wrap before the end of file */
3825 if (feed->feed_max_size && feed->feed_max_size < feed->feed_size)
3826 feed->feed_max_size = feed->feed_size;
3832 /* compute the bandwidth used by each stream */
3833 static void compute_bandwidth(void)
3839 for(stream = first_stream; stream; stream = stream->next) {
3841 for(i=0;i<stream->nb_streams;i++) {
3842 AVStream *st = stream->streams[i];
3843 switch(st->codec->codec_type) {
3844 case AVMEDIA_TYPE_AUDIO:
3845 case AVMEDIA_TYPE_VIDEO:
3846 bandwidth += st->codec->bit_rate;
3852 stream->bandwidth = (bandwidth + 999) / 1000;
3856 /* add a codec and set the default parameters */
3857 static void add_codec(FFStream *stream, AVCodecContext *av)
3861 if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams))
3864 /* compute default parameters */
3865 switch(av->codec_type) {
3866 case AVMEDIA_TYPE_AUDIO:
3867 if (av->bit_rate == 0)
3868 av->bit_rate = 64000;
3869 if (av->sample_rate == 0)
3870 av->sample_rate = 22050;
3871 if (av->channels == 0)
3874 case AVMEDIA_TYPE_VIDEO:
3875 if (av->bit_rate == 0)
3876 av->bit_rate = 64000;
3877 if (av->time_base.num == 0){
3878 av->time_base.den = 5;
3879 av->time_base.num = 1;
3881 if (av->width == 0 || av->height == 0) {
3885 /* Bitrate tolerance is less for streaming */
3886 if (av->bit_rate_tolerance == 0)
3887 av->bit_rate_tolerance = FFMAX(av->bit_rate / 4,
3888 (int64_t)av->bit_rate*av->time_base.num/av->time_base.den);
3893 if (av->max_qdiff == 0)
3895 av->qcompress = 0.5;
3898 if (!av->nsse_weight)
3899 av->nsse_weight = 8;
3901 av->frame_skip_cmp = FF_CMP_DCTMAX;
3903 av->me_method = ME_EPZS;
3904 av->rc_buffer_aggressivity = 1.0;
3907 av->rc_eq = av_strdup("tex^qComp");
3908 if (!av->i_quant_factor)
3909 av->i_quant_factor = -0.8;
3910 if (!av->b_quant_factor)
3911 av->b_quant_factor = 1.25;
3912 if (!av->b_quant_offset)
3913 av->b_quant_offset = 1.25;
3914 if (!av->rc_max_rate)
3915 av->rc_max_rate = av->bit_rate * 2;
3917 if (av->rc_max_rate && !av->rc_buffer_size) {
3918 av->rc_buffer_size = av->rc_max_rate;
3927 st = av_mallocz(sizeof(AVStream));
3930 st->codec = avcodec_alloc_context3(NULL);
3931 stream->streams[stream->nb_streams++] = st;
3932 memcpy(st->codec, av, sizeof(AVCodecContext));
3935 static enum AVCodecID opt_codec(const char *name, enum AVMediaType type)
3937 AVCodec *codec = avcodec_find_encoder_by_name(name);
3939 if (!codec || codec->type != type)
3940 return AV_CODEC_ID_NONE;
3944 static int ffserver_opt_default(const char *opt, const char *arg,
3945 AVCodecContext *avctx, int type)
3948 const AVOption *o = av_opt_find(avctx, opt, NULL, type, 0);
3950 ret = av_opt_set(avctx, opt, arg, 0);
3954 static int ffserver_opt_preset(const char *arg,
3955 AVCodecContext *avctx, int type,
3956 enum AVCodecID *audio_id, enum AVCodecID *video_id)
3959 char filename[1000], tmp[1000], tmp2[1000], line[1000];
3961 AVCodec *codec = avcodec_find_encoder(avctx->codec_id);
3963 if (!(f = get_preset_file(filename, sizeof(filename), arg, 0,
3964 codec ? codec->name : NULL))) {
3965 fprintf(stderr, "File for preset '%s' not found\n", arg);
3970 int e= fscanf(f, "%999[^\n]\n", line) - 1;
3971 if(line[0] == '#' && !e)
3973 e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2;
3975 fprintf(stderr, "%s: Invalid syntax: '%s'\n", filename, line);
3979 if(!strcmp(tmp, "acodec")){
3980 *audio_id = opt_codec(tmp2, AVMEDIA_TYPE_AUDIO);
3981 }else if(!strcmp(tmp, "vcodec")){
3982 *video_id = opt_codec(tmp2, AVMEDIA_TYPE_VIDEO);
3983 }else if(!strcmp(tmp, "scodec")){
3984 /* opt_subtitle_codec(tmp2); */
3985 }else if(ffserver_opt_default(tmp, tmp2, avctx, type) < 0){
3986 fprintf(stderr, "%s: Invalid option or argument: '%s', parsed as '%s' = '%s'\n", filename, line, tmp, tmp2);
3997 static AVOutputFormat *ffserver_guess_format(const char *short_name, const char *filename, const char *mime_type)
3999 AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type);
4002 AVOutputFormat *stream_fmt;
4003 char stream_format_name[64];
4005 snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", fmt->name);
4006 stream_fmt = av_guess_format(stream_format_name, NULL, NULL);
4015 static void report_config_error(const char *filename, int line_num, int log_level, int *errors, const char *fmt, ...)
4019 av_log(NULL, log_level, "%s:%d: ", filename, line_num);
4020 av_vlog(NULL, log_level, fmt, vl);
4026 static int parse_ffconfig(const char *filename)
4031 char arg[1024], arg2[1024];
4033 int val, errors, warnings, line_num;
4034 FFStream **last_stream, *stream, *redirect;
4035 FFStream **last_feed, *feed, *s;
4036 AVCodecContext audio_enc, video_enc;
4037 enum AVCodecID audio_id, video_id;
4040 f = fopen(filename, "r");
4042 ret = AVERROR(errno);
4043 av_log(NULL, AV_LOG_ERROR, "Could not open the configuration file '%s'\n", filename);
4047 errors = warnings = 0;
4049 first_stream = NULL;
4050 last_stream = &first_stream;
4052 last_feed = &first_feed;
4056 audio_id = AV_CODEC_ID_NONE;
4057 video_id = AV_CODEC_ID_NONE;
4058 #define ERROR(...) report_config_error(filename, line_num, AV_LOG_ERROR, &errors, __VA_ARGS__)
4059 #define WARNING(...) report_config_error(filename, line_num, AV_LOG_WARNING, &warnings, __VA_ARGS__)
4062 if (fgets(line, sizeof(line), f) == NULL)
4066 while (av_isspace(*p))
4068 if (*p == '\0' || *p == '#')
4071 get_arg(cmd, sizeof(cmd), &p);
4073 if (!av_strcasecmp(cmd, "Port") || !av_strcasecmp(cmd, "HTTPPort")) {
4074 if (!av_strcasecmp(cmd, "Port"))
4075 WARNING("Port option is deprecated, use HTTPPort instead\n");
4076 get_arg(arg, sizeof(arg), &p);
4078 if (val < 1 || val > 65536) {
4079 ERROR("Invalid port: %s\n", arg);
4082 WARNING("Trying to use IETF assigned system port: %d\n", val);
4083 my_http_addr.sin_port = htons(val);
4084 } else if (!av_strcasecmp(cmd, "HTTPBindAddress") || !av_strcasecmp(cmd, "BindAddress")) {
4085 if (!av_strcasecmp(cmd, "BindAddress"))
4086 WARNING("BindAddress option is deprecated, use HTTPBindAddress instead\n");
4087 get_arg(arg, sizeof(arg), &p);
4088 if (resolve_host(&my_http_addr.sin_addr, arg) != 0) {
4089 ERROR("%s:%d: Invalid host/IP address: %s\n", arg);
4091 } else if (!av_strcasecmp(cmd, "NoDaemon")) {
4092 WARNING("NoDaemon option has no effect, you should remove it\n");
4093 } else if (!av_strcasecmp(cmd, "RTSPPort")) {
4094 get_arg(arg, sizeof(arg), &p);
4096 if (val < 1 || val > 65536) {
4097 ERROR("%s:%d: Invalid port: %s\n", arg);
4099 my_rtsp_addr.sin_port = htons(atoi(arg));
4100 } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) {
4101 get_arg(arg, sizeof(arg), &p);
4102 if (resolve_host(&my_rtsp_addr.sin_addr, arg) != 0) {
4103 ERROR("Invalid host/IP address: %s\n", arg);
4105 } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) {
4106 get_arg(arg, sizeof(arg), &p);
4108 if (val < 1 || val > 65536) {
4109 ERROR("Invalid MaxHTTPConnections: %s\n", arg);
4111 nb_max_http_connections = val;
4112 } else if (!av_strcasecmp(cmd, "MaxClients")) {
4113 get_arg(arg, sizeof(arg), &p);
4115 if (val < 1 || val > nb_max_http_connections) {
4116 ERROR("Invalid MaxClients: %s\n", arg);
4118 nb_max_connections = val;
4120 } else if (!av_strcasecmp(cmd, "MaxBandwidth")) {
4122 get_arg(arg, sizeof(arg), &p);
4123 llval = strtoll(arg, NULL, 10);
4124 if (llval < 10 || llval > 10000000) {
4125 ERROR("Invalid MaxBandwidth: %s\n", arg);
4127 max_bandwidth = llval;
4128 } else if (!av_strcasecmp(cmd, "CustomLog")) {
4129 if (!ffserver_debug)
4130 get_arg(logfilename, sizeof(logfilename), &p);
4131 } else if (!av_strcasecmp(cmd, "<Feed")) {
4132 /*********************************************/
4133 /* Feed related options */
4135 if (stream || feed) {
4136 ERROR("Already in a tag\n");
4138 feed = av_mallocz(sizeof(FFStream));
4140 ret = AVERROR(ENOMEM);
4143 get_arg(feed->filename, sizeof(feed->filename), &p);
4144 q = strrchr(feed->filename, '>');
4148 for (s = first_feed; s; s = s->next) {
4149 if (!strcmp(feed->filename, s->filename)) {
4150 ERROR("Feed '%s' already registered\n", s->filename);
4154 feed->fmt = av_guess_format("ffm", NULL, NULL);
4155 /* default feed file */
4156 snprintf(feed->feed_filename, sizeof(feed->feed_filename),
4157 "/tmp/%s.ffm", feed->filename);
4158 feed->feed_max_size = 5 * 1024 * 1024;
4160 feed->feed = feed; /* self feeding :-) */
4162 /* add in stream list */
4163 *last_stream = feed;
4164 last_stream = &feed->next;
4165 /* add in feed list */
4167 last_feed = &feed->next_feed;
4169 } else if (!av_strcasecmp(cmd, "Launch")) {
4173 feed->child_argv = av_mallocz(64 * sizeof(char *));
4174 if (!feed->child_argv) {
4175 ret = AVERROR(ENOMEM);
4178 for (i = 0; i < 62; i++) {
4179 get_arg(arg, sizeof(arg), &p);
4183 feed->child_argv[i] = av_strdup(arg);
4184 if (!feed->child_argv[i]) {
4185 ret = AVERROR(ENOMEM);
4190 feed->child_argv[i] =
4191 av_asprintf("http://%s:%d/%s",
4192 (my_http_addr.sin_addr.s_addr == INADDR_ANY) ? "127.0.0.1" :
4193 inet_ntoa(my_http_addr.sin_addr), ntohs(my_http_addr.sin_port),
4195 if (!feed->child_argv[i]) {
4196 ret = AVERROR(ENOMEM);
4200 } else if (!av_strcasecmp(cmd, "File") || !av_strcasecmp(cmd, "ReadOnlyFile")) {
4202 get_arg(feed->feed_filename, sizeof(feed->feed_filename), &p);
4203 feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile");
4204 } else if (stream) {
4205 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4207 } else if (!av_strcasecmp(cmd, "Truncate")) {
4209 get_arg(arg, sizeof(arg), &p);
4210 /* assume Truncate is true in case no argument is specified */
4214 WARNING("Truncate N syntax in configuration file is deprecated, "
4215 "use Truncate alone with no arguments\n");
4216 feed->truncate = strtod(arg, NULL);
4219 } else if (!av_strcasecmp(cmd, "FileMaxSize")) {
4224 get_arg(arg, sizeof(arg), &p);
4226 fsize = strtod(p1, &p1);
4227 switch(av_toupper(*p1)) {
4232 fsize *= 1024 * 1024;
4235 fsize *= 1024 * 1024 * 1024;
4238 feed->feed_max_size = (int64_t)fsize;
4239 if (feed->feed_max_size < FFM_PACKET_SIZE*4) {
4240 ERROR("Feed max file size is too small, must be at least %d\n", FFM_PACKET_SIZE*4);
4243 } else if (!av_strcasecmp(cmd, "</Feed>")) {
4245 ERROR("No corresponding <Feed> for </Feed>\n");
4248 } else if (!av_strcasecmp(cmd, "<Stream")) {
4249 /*********************************************/
4250 /* Stream related options */
4252 if (stream || feed) {
4253 ERROR("Already in a tag\n");
4256 stream = av_mallocz(sizeof(FFStream));
4258 ret = AVERROR(ENOMEM);
4261 get_arg(stream->filename, sizeof(stream->filename), &p);
4262 q = strrchr(stream->filename, '>');
4266 for (s = first_stream; s; s = s->next) {
4267 if (!strcmp(stream->filename, s->filename)) {
4268 ERROR("Stream '%s' already registered\n", s->filename);
4272 stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL);
4273 avcodec_get_context_defaults3(&video_enc, NULL);
4274 avcodec_get_context_defaults3(&audio_enc, NULL);
4276 audio_id = AV_CODEC_ID_NONE;
4277 video_id = AV_CODEC_ID_NONE;
4279 audio_id = stream->fmt->audio_codec;
4280 video_id = stream->fmt->video_codec;
4283 *last_stream = stream;
4284 last_stream = &stream->next;
4286 } else if (!av_strcasecmp(cmd, "Feed")) {
4287 get_arg(arg, sizeof(arg), &p);
4293 if (!strcmp(sfeed->filename, arg))
4295 sfeed = sfeed->next_feed;
4298 ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg, stream->filename);
4300 stream->feed = sfeed;
4302 } else if (!av_strcasecmp(cmd, "Format")) {
4303 get_arg(arg, sizeof(arg), &p);
4305 if (!strcmp(arg, "status")) {
4306 stream->stream_type = STREAM_TYPE_STATUS;
4309 stream->stream_type = STREAM_TYPE_LIVE;
4310 /* JPEG cannot be used here, so use single frame MJPEG */
4311 if (!strcmp(arg, "jpeg"))
4312 strcpy(arg, "mjpeg");
4313 stream->fmt = ffserver_guess_format(arg, NULL, NULL);
4315 ERROR("Unknown Format: %s\n", arg);
4319 audio_id = stream->fmt->audio_codec;
4320 video_id = stream->fmt->video_codec;
4323 } else if (!av_strcasecmp(cmd, "InputFormat")) {
4324 get_arg(arg, sizeof(arg), &p);
4326 stream->ifmt = av_find_input_format(arg);
4327 if (!stream->ifmt) {
4328 ERROR("Unknown input format: %s\n", arg);
4331 } else if (!av_strcasecmp(cmd, "FaviconURL")) {
4332 if (stream && stream->stream_type == STREAM_TYPE_STATUS) {
4333 get_arg(stream->feed_filename, sizeof(stream->feed_filename), &p);
4335 ERROR("FaviconURL only permitted for status streams\n");
4337 } else if (!av_strcasecmp(cmd, "Author") ||
4338 !av_strcasecmp(cmd, "Comment") ||
4339 !av_strcasecmp(cmd, "Copyright") ||
4340 !av_strcasecmp(cmd, "Title")) {
4341 get_arg(arg, sizeof(arg), &p);
4347 for (i = 0; i < strlen(cmd); i++)
4348 key[i] = av_tolower(cmd[i]);
4350 WARNING("'%s' option in configuration file is deprecated, "
4351 "use 'Metadata %s VALUE' instead\n", cmd, key);
4352 if ((ret = av_dict_set(&stream->metadata, key, arg, 0)) < 0) {
4353 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4354 key, arg, av_err2str(ret));
4357 } else if (!av_strcasecmp(cmd, "Metadata")) {
4358 get_arg(arg, sizeof(arg), &p);
4359 get_arg(arg2, sizeof(arg2), &p);
4362 if ((ret = av_dict_set(&stream->metadata, arg, arg2, 0)) < 0) {
4363 ERROR("Could not set metadata '%s' to value '%s': %s\n",
4364 arg, arg2, av_err2str(ret));
4367 } else if (!av_strcasecmp(cmd, "Preroll")) {
4368 get_arg(arg, sizeof(arg), &p);
4370 stream->prebuffer = atof(arg) * 1000;
4371 } else if (!av_strcasecmp(cmd, "StartSendOnKey")) {
4373 stream->send_on_key = 1;
4374 } else if (!av_strcasecmp(cmd, "AudioCodec")) {
4375 get_arg(arg, sizeof(arg), &p);
4376 audio_id = opt_codec(arg, AVMEDIA_TYPE_AUDIO);
4377 if (audio_id == AV_CODEC_ID_NONE) {
4378 ERROR("Unknown AudioCodec: %s\n", arg);
4380 } else if (!av_strcasecmp(cmd, "VideoCodec")) {
4381 get_arg(arg, sizeof(arg), &p);
4382 video_id = opt_codec(arg, AVMEDIA_TYPE_VIDEO);
4383 if (video_id == AV_CODEC_ID_NONE) {
4384 ERROR("Unknown VideoCodec: %s\n", arg);
4386 } else if (!av_strcasecmp(cmd, "MaxTime")) {
4387 get_arg(arg, sizeof(arg), &p);
4389 stream->max_time = atof(arg) * 1000;
4390 } else if (!av_strcasecmp(cmd, "AudioBitRate")) {
4391 get_arg(arg, sizeof(arg), &p);
4393 audio_enc.bit_rate = lrintf(atof(arg) * 1000);
4394 } else if (!av_strcasecmp(cmd, "AudioChannels")) {
4395 get_arg(arg, sizeof(arg), &p);
4397 audio_enc.channels = atoi(arg);
4398 } else if (!av_strcasecmp(cmd, "AudioSampleRate")) {
4399 get_arg(arg, sizeof(arg), &p);
4401 audio_enc.sample_rate = atoi(arg);
4402 } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) {
4404 int minrate, maxrate;
4406 get_arg(arg, sizeof(arg), &p);
4408 if (sscanf(arg, "%d-%d", &minrate, &maxrate) == 2) {
4409 video_enc.rc_min_rate = minrate * 1000;
4410 video_enc.rc_max_rate = maxrate * 1000;
4412 ERROR("Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s\n", arg);
4415 } else if (!av_strcasecmp(cmd, "Debug")) {
4417 get_arg(arg, sizeof(arg), &p);
4418 video_enc.debug = strtol(arg,0,0);
4420 } else if (!av_strcasecmp(cmd, "Strict")) {
4422 get_arg(arg, sizeof(arg), &p);
4423 video_enc.strict_std_compliance = atoi(arg);
4425 } else if (!av_strcasecmp(cmd, "VideoBufferSize")) {
4427 get_arg(arg, sizeof(arg), &p);
4428 video_enc.rc_buffer_size = atoi(arg) * 8*1024;
4430 } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) {
4432 get_arg(arg, sizeof(arg), &p);
4433 video_enc.bit_rate_tolerance = atoi(arg) * 1000;
4435 } else if (!av_strcasecmp(cmd, "VideoBitRate")) {
4436 get_arg(arg, sizeof(arg), &p);
4438 video_enc.bit_rate = atoi(arg) * 1000;
4440 } else if (!av_strcasecmp(cmd, "VideoSize")) {
4441 get_arg(arg, sizeof(arg), &p);
4443 ret = av_parse_video_size(&video_enc.width, &video_enc.height, arg);
4445 ERROR("Invalid video size '%s'\n", arg);
4447 if ((video_enc.width % 16) != 0 ||
4448 (video_enc.height % 16) != 0) {
4449 ERROR("Image size must be a multiple of 16\n");
4453 } else if (!av_strcasecmp(cmd, "VideoFrameRate")) {
4454 get_arg(arg, sizeof(arg), &p);
4456 AVRational frame_rate;
4457 if (av_parse_video_rate(&frame_rate, arg) < 0) {
4458 ERROR("Incorrect frame rate: %s\n", arg);
4460 video_enc.time_base.num = frame_rate.den;
4461 video_enc.time_base.den = frame_rate.num;
4464 } else if (!av_strcasecmp(cmd, "PixelFormat")) {
4465 get_arg(arg, sizeof(arg), &p);
4467 video_enc.pix_fmt = av_get_pix_fmt(arg);
4468 if (video_enc.pix_fmt == AV_PIX_FMT_NONE) {
4469 ERROR("Unknown pixel format: %s\n", arg);
4472 } else if (!av_strcasecmp(cmd, "VideoGopSize")) {
4473 get_arg(arg, sizeof(arg), &p);
4475 video_enc.gop_size = atoi(arg);
4476 } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) {
4478 video_enc.gop_size = 1;
4479 } else if (!av_strcasecmp(cmd, "VideoHighQuality")) {
4481 video_enc.mb_decision = FF_MB_DECISION_BITS;
4482 } else if (!av_strcasecmp(cmd, "Video4MotionVector")) {
4484 video_enc.mb_decision = FF_MB_DECISION_BITS; //FIXME remove
4485 video_enc.flags |= CODEC_FLAG_4MV;
4487 } else if (!av_strcasecmp(cmd, "AVOptionVideo") ||
4488 !av_strcasecmp(cmd, "AVOptionAudio")) {
4489 AVCodecContext *avctx;
4491 get_arg(arg, sizeof(arg), &p);
4492 get_arg(arg2, sizeof(arg2), &p);
4493 if (!av_strcasecmp(cmd, "AVOptionVideo")) {
4495 type = AV_OPT_FLAG_VIDEO_PARAM;
4498 type = AV_OPT_FLAG_AUDIO_PARAM;
4500 if (ffserver_opt_default(arg, arg2, avctx, type|AV_OPT_FLAG_ENCODING_PARAM)) {
4501 ERROR("Error setting %s option to %s %s\n", cmd, arg, arg2);
4503 } else if (!av_strcasecmp(cmd, "AVPresetVideo") ||
4504 !av_strcasecmp(cmd, "AVPresetAudio")) {
4505 AVCodecContext *avctx;
4507 get_arg(arg, sizeof(arg), &p);
4508 if (!av_strcasecmp(cmd, "AVPresetVideo")) {
4510 video_enc.codec_id = video_id;
4511 type = AV_OPT_FLAG_VIDEO_PARAM;
4514 audio_enc.codec_id = audio_id;
4515 type = AV_OPT_FLAG_AUDIO_PARAM;
4517 if (ffserver_opt_preset(arg, avctx, type|AV_OPT_FLAG_ENCODING_PARAM, &audio_id, &video_id)) {
4518 ERROR("AVPreset error: %s\n", arg);
4520 } else if (!av_strcasecmp(cmd, "VideoTag")) {
4521 get_arg(arg, sizeof(arg), &p);
4522 if ((strlen(arg) == 4) && stream)
4523 video_enc.codec_tag = MKTAG(arg[0], arg[1], arg[2], arg[3]);
4524 } else if (!av_strcasecmp(cmd, "BitExact")) {
4526 video_enc.flags |= CODEC_FLAG_BITEXACT;
4527 } else if (!av_strcasecmp(cmd, "DctFastint")) {
4529 video_enc.dct_algo = FF_DCT_FASTINT;
4530 } else if (!av_strcasecmp(cmd, "IdctSimple")) {
4532 video_enc.idct_algo = FF_IDCT_SIMPLE;
4533 } else if (!av_strcasecmp(cmd, "Qscale")) {
4534 get_arg(arg, sizeof(arg), &p);
4536 video_enc.flags |= CODEC_FLAG_QSCALE;
4537 video_enc.global_quality = FF_QP2LAMBDA * atoi(arg);
4539 } else if (!av_strcasecmp(cmd, "VideoQDiff")) {
4540 get_arg(arg, sizeof(arg), &p);
4542 video_enc.max_qdiff = atoi(arg);
4543 if (video_enc.max_qdiff < 1 || video_enc.max_qdiff > 31) {
4544 ERROR("VideoQDiff out of range\n");
4547 } else if (!av_strcasecmp(cmd, "VideoQMax")) {
4548 get_arg(arg, sizeof(arg), &p);
4550 video_enc.qmax = atoi(arg);
4551 if (video_enc.qmax < 1 || video_enc.qmax > 31) {
4552 ERROR("VideoQMax out of range\n");
4555 } else if (!av_strcasecmp(cmd, "VideoQMin")) {
4556 get_arg(arg, sizeof(arg), &p);
4558 video_enc.qmin = atoi(arg);
4559 if (video_enc.qmin < 1 || video_enc.qmin > 31) {
4560 ERROR("VideoQMin out of range\n");
4563 } else if (!av_strcasecmp(cmd, "LumiMask")) {
4564 get_arg(arg, sizeof(arg), &p);
4566 video_enc.lumi_masking = atof(arg);
4567 } else if (!av_strcasecmp(cmd, "DarkMask")) {
4568 get_arg(arg, sizeof(arg), &p);
4570 video_enc.dark_masking = atof(arg);
4571 } else if (!av_strcasecmp(cmd, "NoVideo")) {
4572 video_id = AV_CODEC_ID_NONE;
4573 } else if (!av_strcasecmp(cmd, "NoAudio")) {
4574 audio_id = AV_CODEC_ID_NONE;
4575 } else if (!av_strcasecmp(cmd, "ACL")) {
4576 parse_acl_row(stream, feed, NULL, p, filename, line_num);
4577 } else if (!av_strcasecmp(cmd, "DynamicACL")) {
4579 get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), &p);
4581 } else if (!av_strcasecmp(cmd, "RTSPOption")) {
4582 get_arg(arg, sizeof(arg), &p);
4584 av_freep(&stream->rtsp_option);
4585 stream->rtsp_option = av_strdup(arg);
4587 } else if (!av_strcasecmp(cmd, "MulticastAddress")) {
4588 get_arg(arg, sizeof(arg), &p);
4590 if (resolve_host(&stream->multicast_ip, arg) != 0) {
4591 ERROR("Invalid host/IP address: %s\n", arg);
4593 stream->is_multicast = 1;
4594 stream->loop = 1; /* default is looping */
4596 } else if (!av_strcasecmp(cmd, "MulticastPort")) {
4597 get_arg(arg, sizeof(arg), &p);
4599 stream->multicast_port = atoi(arg);
4600 } else if (!av_strcasecmp(cmd, "MulticastTTL")) {
4601 get_arg(arg, sizeof(arg), &p);
4603 stream->multicast_ttl = atoi(arg);
4604 } else if (!av_strcasecmp(cmd, "NoLoop")) {
4607 } else if (!av_strcasecmp(cmd, "</Stream>")) {
4609 ERROR("No corresponding <Stream> for </Stream>\n");
4611 if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm") != 0) {
4612 if (audio_id != AV_CODEC_ID_NONE) {
4613 audio_enc.codec_type = AVMEDIA_TYPE_AUDIO;
4614 audio_enc.codec_id = audio_id;
4615 add_codec(stream, &audio_enc);
4617 if (video_id != AV_CODEC_ID_NONE) {
4618 video_enc.codec_type = AVMEDIA_TYPE_VIDEO;
4619 video_enc.codec_id = video_id;
4620 add_codec(stream, &video_enc);
4625 } else if (!av_strcasecmp(cmd, "<Redirect")) {
4626 /*********************************************/
4628 if (stream || feed || redirect) {
4629 ERROR("Already in a tag\n");
4631 redirect = av_mallocz(sizeof(FFStream));
4633 ret = AVERROR(ENOMEM);
4636 *last_stream = redirect;
4637 last_stream = &redirect->next;
4639 get_arg(redirect->filename, sizeof(redirect->filename), &p);
4640 q = strrchr(redirect->filename, '>');
4643 redirect->stream_type = STREAM_TYPE_REDIRECT;
4645 } else if (!av_strcasecmp(cmd, "URL")) {
4647 get_arg(redirect->feed_filename, sizeof(redirect->feed_filename), &p);
4648 } else if (!av_strcasecmp(cmd, "</Redirect>")) {
4650 ERROR("No corresponding <Redirect> for </Redirect>\n");
4652 if (!redirect->feed_filename[0]) {
4653 ERROR("No URL found for <Redirect>\n");
4657 } else if (!av_strcasecmp(cmd, "LoadModule")) {
4658 ERROR("Loadable modules no longer supported\n");
4660 ERROR("Incorrect keyword: '%s'\n", cmd);
4670 return AVERROR(EINVAL);
4675 static void handle_child_exit(int sig)
4680 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
4683 for (feed = first_feed; feed; feed = feed->next) {
4684 if (feed->pid == pid) {
4685 int uptime = time(0) - feed->pid_start;
4688 fprintf(stderr, "%s: Pid %d exited with status %d after %d seconds\n", feed->filename, pid, status, uptime);
4691 /* Turn off any more restarts */
4692 feed->child_argv = 0;
4697 need_to_start_children = 1;
4700 static void opt_debug(void)
4703 logfilename[0] = '-';
4706 void show_help_default(const char *opt, const char *arg)
4708 printf("usage: ffserver [options]\n"
4709 "Hyper fast multi format Audio/Video streaming server\n");
4711 show_help_options(options, "Main options:", 0, 0, 0);
4714 static const OptionDef options[] = {
4715 #include "cmdutils_common_opts.h"
4716 { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" },
4717 { "d", 0, {(void*)opt_debug}, "enable debug mode" },
4718 { "f", HAS_ARG | OPT_STRING, {(void*)&config_filename }, "use configfile instead of /etc/ffserver.conf", "configfile" },
4722 int main(int argc, char **argv)
4724 struct sigaction sigact = { { 0 } };
4727 config_filename = av_strdup("/etc/ffserver.conf");
4729 parse_loglevel(argc, argv, options);
4731 avformat_network_init();
4733 show_banner(argc, argv, options);
4735 my_program_name = argv[0];
4737 parse_options(NULL, argc, argv, options, NULL);
4739 unsetenv("http_proxy"); /* Kill the http_proxy */
4741 av_lfg_init(&random_state, av_get_random_seed());
4743 sigact.sa_handler = handle_child_exit;
4744 sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART;
4745 sigaction(SIGCHLD, &sigact, 0);
4747 if ((ret = parse_ffconfig(config_filename)) < 0) {
4748 fprintf(stderr, "Error reading configuration file '%s': %s\n",
4749 config_filename, av_err2str(ret));
4752 av_freep(&config_filename);
4754 /* open log file if needed */
4755 if (logfilename[0] != '\0') {
4756 if (!strcmp(logfilename, "-"))
4759 logfile = fopen(logfilename, "a");
4760 av_log_set_callback(http_av_log);
4763 build_file_streams();
4765 build_feed_streams();
4767 compute_bandwidth();
4770 signal(SIGPIPE, SIG_IGN);
4772 if (http_server() < 0) {
4773 http_log("Could not start server\n");